zoukankan      html  css  js  c++  java
  • react核心知识点高度总结

    本文系统的将react的语法以最简练的方式列举出来

    此文更新于2019/1/18

    安装

    npx create-react-app my-app
    cd my-app
    npm start
    

    写在前面

    1. react中state的属性,不要直接修改,而要使用替换的方式
    
    2. 只做渲染处理的组件,尽量使用函数式组件,如下
        function Square(props) {
            return (
                <button className="square" onClick={() => props.onClick()}>
                    {props.value}
                </button>
            );
        }
    
    3. 相同的一组组件必须要添加key
    
    4. jsx中的属性值必须使用花括号包裹
    
    5. jsx中的属性名必须使用驼峰命名法
    
    6. 用户自定义的组件名必须使用大写开头
    
    7. 组件内部不能修改props
    
    8. 事件内部不能使用return false而只能使用e.preventDefault()阻止默认行为
    
    9. 在组件中使用key,是不能通过props访问到的
    
    10. false,true,null,undefined 使用{}都不会显示
    
    11. ref的回调函数,在组件载入和销毁的时候都会调用
    
    12. react中,你要为表单元素添加默认值,必须使用defaultValue
    
    13. props和state属性如果是引用类型,不能直接改变,否则不会触发react的刷新机制
    
    14. context的更新没有很好的办法,因为context的更新是依赖于state和props的更新
    
    15. 在react里面引用类型中的属性修改了,照样可以更新视图,下面这段代码是会更新的,这也是为什么要有PureComponent的目的,减少不必要的人为更新
        constructor(props){
            super(props);
            this.state = {
                obj: {
                    name: "叶家伟"
                }
            }
        }
        componentDidMount(){
            var obj = this.state.obj;
            obj.name = "哈哈哈";
            window.setTimeout(() => {
                this.setState({
                    obj: obj
                });
            }, 2000)
        }
    
    16. 之前写代码,如果要返回多个元素需要单独添加一个div去包裹,现在可以使用Fragments
        <React.Fragment>
          <ChildA />
          <ChildB />
          <ChildC />
        </React.Fragment>
    

    JSX

    简单明了的概括:jsx就是将html当作表达式使用
    
    const text = "啊哈哈哈哈";
    const cn = "App";
    const element = <div className={cn}>{text}</div>;
    class App extends Component {
        render() {
            return (
                element
            );
        }
    }
    

    组件的定义

    function Fc(props){
        return <h1>我是props, {props.data}</h1>
    }   // 函数式组件
    class App extends Component {   // 类定义的组件
      render() {
        return (
            <div className="App">
                <Fc data="啊哈哈哈哈" />
            </div>
        );
      }
    }
    

    state

    class MyComponent extends React.Component {
        constructor (props) {
            super(props);
            this.state = {name: "yejiawei"}
        }
        componentDidMount() {
            this.setState({
                name: "haha" // 修改值
            })
            this.setState({
                name: this.state.name + "haha" // 异步刷新,无法展示最新值
            })
            this.setState((prevState,props) => ({
                name: prevState.name + "haha" // 等待异步刷新完成,展示最新值
            }))
        }
        render() {
            return (
                <p>{this.state.name}</p>
            )
        }
    }
    

    生命周期

    componentWillMount() {} 挂载之前
    componentDidMount() {} 挂载
    componentWillUnmount() {} 销毁
    componentWillReceiveProps(){} 接受props
    componentWillUpdate() {} 更新
    

    方法

    1. 使用bind

      class MyComponent extends React.Component {
          constructor () {
              super();
              this.state = {name: "yejiawei"};
              this.alertInfo = this.alertInfo.bind(this);
          }
          alertInfo(){
              alert(this.state.name)
          }
          render() {
              return (
                  <p onClick={this.alertInfo}>{this.state.name}</p>
              )
          }
      }
      
    2. 使用箭头函数

      class MyComponent extends React.Component {
          constructor () {
              super();
              this.state = {name: "yejiawei"};
          }
          alertInfo = () => {
              alert(this.state.name)
          }
          render() {
              return (
                  <p onClick={this.alertInfo}>{this.state.name}</p>
              )
          }
      }
      
    3. 不推荐的语法

      class MyComponent extends React.Component {
          constructor () {
              super();
              this.state = {name: "yejiawei"};
          }
          alertInfo(){
              alert(this.state.name)
          }
          render() {
              return (
                  <p onClick={() => {this.alertInfo()}}>{this.state.name}</p>
              )
          }
      }
      

    条件渲染

    1. if切换

      
      function MyComponent1() {
          return (
              <p>我是组件1</p>
          )
      }
      function MyComponent2() {
          return (
              <p>我是组件2</p>
          )
      }
      class MyComponent extends React.Component {
          constructor() {
              super();
              this.state = {
              isComponent1: true
              }
          }
          changeComponent = () => {
              this.setState({
                  isComponent1: !this.state.isComponent1
              })
          }
          render() {
              let Comp = null;
              if(this.state.isComponent1) {
                  Comp = <MyComponent1 />
              } else {
                  Comp = <MyComponent2 />
              }
              return (
                  <div>
                      <button onClick={this.changeComponent}>切换</button>
                      {Comp}
                  </div>
              )
          }
      }
      
    2. 短路操作

      function MyComponent1(props) {
          return (
              <div>
                  {props.isShow &&  <p>我是组件1</p> }
              </div>
          )
      }
      class MyComponent extends React.Component {
          constructor() {
              super();
              this.state = {
                  isComponent1: true
              }
          }
          changeComponent = () => {
              this.setState({
                  isComponent1: !this.state.isComponent1
              })
          }
          render() {
              return (
                  <div>
                      <button onClick={this.changeComponent}>显示隐藏</button>
                      <MyComponent1 isShow={this.state.isComponent1} />
                  </div>
              )
          }
      }
      
    3. 三元运算符

      function MyComponent1(props) {
          return (
              <div>
                  { props.isShow? <p>我是组件1</p>: <p>我是组件2</p> }
              </div>
          )
      }
      
    4. 返回null

      function MyComponent1(props) {
          if(!props.isShow) {
              return null;
          }
          return (
              <div>
                  <p>我是组件1</p>
              </div>
          )
      }
      

    列表

    基本原理 
    class MyComponent extends React.Component {
        render() {
            let arr = [1,2,3,4,5];
            const componentArr = arr.map((item,index) => {
                return <li key={index}>{item}</li>
            })
            return (
                <ul>
                    {componentArr}
                </ul>
            )
        }
    }
    必须指定key
    

    表单

    // 现实开发中,由于都是用ui框架处理,这部分很少涉及,了解下即可
    
    实现自己的双向数据绑定
    class MyComponent extends React.Component {
        constructor () {
            super();
            this.state = {
                name: '',
                age: ''
            }
        }
        setValue = (e) => {
            this.setState({
                [e.target.name]: e.target.value
            })
        }
        sendData = (e) => {
            e.preventDefault();
            alert('提交的数据:' + this.state.value)
        }
        render() {
            return (
            <form onSubmit={this.sendData}>
                <label>Name: <input name="name" type="text" value={this.state.name} onChange={this.setValue} /></label>
                <label>Age: <input name="age" type="text" value={this.state.age} onChange={this.setValue} /></label>
                <input type="submit" value="提交" /><br />
                {this.state.name + ':' + this.state.age}
            </form>
            )
        }
    }
    

    组合嵌套

    这部分内容和vue的slot很像
    组件嵌套的元素使用 props.children 表示
        function MyComponent1 (props) {
            return (
                <div>{props.children}</div>
            )
        }
        function MyComponent (props) {
            return (
                <MyComponent1>
                    <h1>我是嵌套的元素</h1>
                </MyComponent1>
            )
        }
    子嵌套
        function MyComponent1 (props) {
            return (
                <div>
                    <div>{props.left}</div>
                    <div>{props.right}</div>
                </div>
            )
        }
        function MyComponent (props) {
            return (
                <MyComponent1 left={<h1>我是左边嵌套的元素</h1>} right={<h1>我是右边嵌套的元素</h1>}/>
            )
        }
    

    扩展语法

    当你的组件属性过多时,可以使用 ... 语法
    function MyComponent () {
        let props = {
            a: 'a',
            b: 'b'
        };
        return <SomeComponent {...props}>
    }
    

    context传递props

    const TestContext = React.createContext('test'); // 创建一个上下文属性,默认值是test
    
    class FcPre extends Component {
        render() {
            return ( // 将上下文属性传递给FcMiddle组件以及它的所有子组件
                <TestContext.Provider value="啊哈哈哈哈哈">
                    <FcMiddle />
                </TestContext.Provider>
            );
        }
    }
    
    function FcMiddle(props){ // 随便写的中间层,可以有n层
        return <h1><FcEnd /></h1>
    }
    
    class FcEnd extends Component {
        static contextType = TestContext; // 将上下文属性读取到组件中来,使用this.context访问属性值
    
        render() {
            return (
                <p>{this.context}</p>
            );
        }
    }
    
    class App extends Component {
      render() {
        return (
            <div className="App">
                <FcPre />
            </div>
        );
      }
    }
    

    错误拦截

    class ErrorBoundary extends React.Component {
        constructor(props) {
            super(props);
            this.state = { hasError: false };
        }
      
        static getDerivedStateFromError(error) {
            // 拦截错误,将state中的hasError修改成true,从而渲染错误页面,而不是整个前端项目挂了
            return { hasError: true };
        }
      
        componentDidCatch(error, info) {
            // 打印错误信息
            console.log(error, info);
        }
      
        render() {
            if (this.state.hasError) {
                // 渲染错误页面
                return <h1>Something went wrong.</h1>;
            }
    
            return this.props.children; 
        }
    }
    
    class App extends Component {
      render() {
        return (
            <div className="App">
                <ErrorBoundary><h1>aaa</h1></ErrorBoundary>
            </div>
        );
      }
    }
    

    ref获取dom元素

    使用新版的ref可以更加直接的获取到子组件的dom元素
    const rf = React.createRef();
    const Fc = React.forwardRef((props, ref) => {
        return (
            <button ref={ref}>
                {props.children}
            </button>
        )
    })
    
    
    class App extends Component {
    
        componentDidMount() {
            console.log(rf.current)
        }
        render() {
            return (
                <div className="App">
                    <Fc ref={rf}>点我</Fc>
                </div>
            );
        }
    }
    

    自带的类型检查

    安装 cnpm install --save prop-types
    react系统自带的类型验证功能,没有typescript强大,可以当做编译过程中的一个补充检查
        import PropTypes from 'prop-types';
        function MyComponent (props){
            return (
                <div>
                    <div>{props.name}</div>
                </div>
            )
        }
        MyComponent.propTypes = { // 大小写看清楚
            name: PropTypes.number
        }
    完整的类型
        MyComponent.propTypes = {
            // 你可以将属性声明为以下 JS 原生类型
            optionalArray: PropTypes.array,
            optionalBool: PropTypes.bool,
            optionalFunc: PropTypes.func,
            optionalNumber: PropTypes.number,
            optionalObject: PropTypes.object,
            optionalString: PropTypes.string,
            optionalSymbol: PropTypes.symbol,
            // 任何可被渲染的元素(包括数字、字符串、子元素或数组)。
            optionalNode: PropTypes.node,
            // 一个 React 元素
            optionalElement: PropTypes.element,
            // 你也可以声明属性为某个类的实例,这里使用 JS 的
            // instanceof 操作符实现。
            optionalMessage: PropTypes.instanceOf(Message),
            // 你也可以限制你的属性值是某个特定值之一
            optionalEnum: PropTypes.oneOf(['News', 'Photos']),
            // 限制它为列举类型之一的对象
            optionalUnion: PropTypes.oneOfType([
                PropTypes.string,
                PropTypes.number,
                PropTypes.instanceOf(Message)
            ]),
            // 一个指定元素类型的数组
            optionalArrayOf: PropTypes.arrayOf(PropTypes.number),
            // 一个指定类型的对象
            optionalObjectOf: PropTypes.objectOf(PropTypes.number),
            // 一个指定属性及其类型的对象
            optionalObjectWithShape: PropTypes.shape({
                color: PropTypes.string,
                fontSize: PropTypes.number
            }),
            // 你也可以在任何 PropTypes 属性后面加上 `isRequired` 
            // 后缀,这样如果这个属性父组件没有提供时,会打印警告信息
            requiredFunc: PropTypes.func.isRequired,
            // 任意类型的数据
            requiredAny: PropTypes.any.isRequired,
            // 你也可以指定一个自定义验证器。它应该在验证失败时返回
            // 一个 Error 对象而不是 `console.warn` 或抛出异常。
            // 不过在 `oneOfType` 中它不起作用。
            customProp: function(props, propName, componentName) {
                if (!/matchme/.test(props[propName])) {
                return new Error(
                    'Invalid prop `' + propName + '` supplied to' +
                    ' `' + componentName + '`. Validation failed.'
                );
                }
            },
            // 不过你可以提供一个自定义的 `arrayOf` 或 `objectOf` 
            // 验证器,它应该在验证失败时返回一个 Error 对象。 它被用
            // 于验证数组或对象的每个值。验证器前两个参数的第一个是数组
            // 或对象本身,第二个是它们对应的键。
            customArrayProp: PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) {
                if (!/matchme/.test(propValue[key])) {
                return new Error(
                    'Invalid prop `' + propFullName + '` supplied to' +
                    ' `' + componentName + '`. Validation failed.'
                );
                }
            })
        };
        MyComponent.defaultProps = {
            // 当属性没有指定的时候,自动添加此默认值,然后再进行验证
            name: 'yejiawei'
        }
    

    shouldComponentUpdate的应用

    react本来的刷新机制,是根据props和state的变化,来更新虚拟dom树从而比较差异,这会导致子组件没有更新也被纳入比较中,浪费性能
    所以,你可以在每一个组件中添加shouldComponentUpdate钩子函数,来手动控制更新,减少没必要的内部算法消耗
    shouldComponentUpdate(nextProps, nextState) {
        return false;
    }
    当然,如果你知道只需要根据某些props或者state的变化更新组件,那么shouldComponentUpdate无疑是最佳的体验
    如果你就是想单纯的避免因为父组件的更新而导致子组件的更新,那么使用PureComponent将是更好的选择
    

    PureComponent纯组件

    PureComponent的设计目的就是根据组件自身的state和prop的变化,判断自己是否应该更新,而不是解析成虚拟dom树,这样会大大降低性能消耗
    应用类型数据更新应该使用新的引用类型
        对于数组,可以使用concat或者扩展运算符
        对于对象,可以使用Object.assign或者扩展运算符
        另外,还可以使用 Immutable.js 插件
    

    子组件移形换位

    class MyComponent1 extends React.Component {
        render() {
            return ReactDOM.createPortal(
                <h1>{this.context.text}</h1>,
                document.getElementById('haha')
            )
        }
    }
    可以将组件的元素渲染到页面上已经存在的其他的dom容器中,使用createPortal方法即可
    
  • 相关阅读:
    北京爱丽丝幻橙科技有限公司
    红杉资本中国基金:创业者背后的创业者
    关于我们_ | 腕表时代watchtimes.com.cn
    当你想放弃的时候,问一下自己你尽力了吗
    李圣杰_百度百科
    范思哲
    DOM Traversal Example | Documentation | Qt Project
    关于QT中evaluateJavaScript()函数返回值的处理问题
    JS获取整个HTML网页代码
    javascript
  • 原文地址:https://www.cnblogs.com/ye-hcj/p/7716363.html
Copyright © 2011-2022 走看看