React学习笔记:组件

组件

将页面按照界面功能进行拆分,每一块界面都拥有自己的独立逻辑(组件),这样可以提高项目代码的可维护性和复用性。
在这里插入图片描述
如上图所示将这个卡片分为三个组件,那么当需要添加一个这样的卡片时,就可以复用这些组件,只需要稍稍改变一下这些组件的文字和一些参数就好了,大大提高了代码的复用性,并且若后期维护需要改变样式那么只需要改变对应组件的样式,所有的卡片的样式都会改变,大大提高了项目的可维护性。

类组件

使用class语法创建的组件就是类组件

  • 类名首字母必需大写。 类中的构造器不是必须要写的,要对实例进行一些初始化的操作,如添加指定属性时才写。
  • 必须继承React.Component父类
  • 必需有render函数,返回 UI 结构,无渲染可返回 null
  • 如果A类继承了B类,且A类中写了构造器,那么A类构造器中的super是必须要调用的。
  • 类中所定义的方法,都放在了类的原型对象上,供实例去使用。
<body>
  <div id="root"></div>
  <script type="text/javascript" src="./js/react.development.js"></script>
  <script type="text/javascript" src="./js/react-dom.development.js"></script>
  <script type="text/javascript" src="./js/babel.min.js"></script>
  <script type="text/babel">
    // 类组件
    class Head extends React.Component {
      render() {
        return (
          <div>
            这是组件
          </div>
        )
      }
    }
    // 根组件
    class App extends React.Component {
      render() {
        return (
          <div>
            <Head />
            <div style={{ height: 200, backgroundColor: 'red' }}>body</div>
          </div>
        );
      }
    }
    // 渲染虚拟dom
    ReactDOM.render(<App />, document.getElementById('root'));
  </script>
</body>

注意

  • render 是放在 MyComponent 的原型对象上,供实例使用。
  • render 中的 this 是 MyComponent 的实例对象 <=> MyComponent组件实例对象。

执行了 ReactDOM.render(<MyComponent/>....... 之后,发生了什么?

  1. React解析组件标签,找到了MyComponent组件。
  2. 发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用到原型上的render方法。
  3. 将render返回的虚拟DOM转为真实DOM,随后呈现在页面中。

上面的这种把所有组件写在一个文件中会导致后期维护很麻烦,所以我们可以把每个组件单独的写在一个文件中,需要使用哪个组件就引入哪个组件。

状态

根据组件是否有状态可以将组件分为有状态组件和无状态组件。

  • 无状态组件:组件本身不定义状态,没有组件生命周期,只负责 UI 渲染。
  • 有状态组件:组件本身有独立数据,拥有组件生命周期,存在交互行为。

对比两种组件
无状态组件由于没有维护状态只做渲染,性能较好。有状态组件提供数据和生命周期,能力更强。

state

state是组件对象最重要的属性, 值是对象(可以包含多个key-value的组合),组件被称为"状态机"。使用state的时候通过this去访问即可,例如:this.state.xxx。下面的 Head 组件是有状态组件,Body 是无状态组件

<body>
  <div id="root"></div>
  <script type="text/javascript" src="./js/react.development.js"></script>
  <script type="text/javascript" src="./js/react-dom.development.js"></script>
  <script type="text/javascript" src="./js/babel.min.js"></script>
  <script type="text/babel">
    // 类组件
    class Head extends React.Component {
      state = {
        name: '孤城浪人',
        age: 18
      }
      render() {
        return (
          <div>
            姓名:{this.state.name}<br />
            年龄:{this.state.age}
          </div>
        )
      }
    }
    class Body extends React.Component {
      render() {
        return (
          <div>
            body
          </div>
        )
      }
    }
    // 根组件
    class App extends React.Component {
      render() {
        return (
          <div>
            <Head />
            <div style={{ height: 200, backgroundColor: 'red' }}>body</div>
          </div>
        );
      }
    }
    // 渲染虚拟dom
    ReactDOM.render(<App />, document.getElementById('root'));
  </script>
</body>
setState

状态(state)不可直接更改,状态必须通过 setState 方法进行更新,且更新是一种浅合并(只会合并相同 key 的值),不是替换。

setState 是“异步”的,多次 setState 会合并。
setState 是“异步”的,合并更新调用 setState 时,将要更新的状态对象,放到一个更新队列中暂存起来(没有立即更新)。如果多次调用 setState 更新状态,状态会进行合并,后面覆盖前面等到所有的操作都执行完毕,React 会拿到最终的状态,然后触发组件更新。这么做的目的是为了提升渲染性能

  • setState 接收一个对象
<body>
  <div id="root"></div>
  <script type="text/javascript" src="./js/react.development.js"></script>
  <script type="text/javascript" src="./js/react-dom.development.js"></script>
  <script type="text/javascript" src="./js/babel.min.js"></script>
  <script type="text/babel">
    // 类组件
    // 根组件
    class App extends React.Component {
      state = {
        count: 0
      }
      addCount = () => {
        this.setState({ count: this.state.count + 2 });
        this.setState({ count: this.state.count + 1 });
      }
      render() {
        return (
          <div>
            <div>
              {this.state.count}
            </div>
            <button onClick={this.addCount}>add</button>
          </div>
        );
      }
    }
    // 渲染虚拟dom
    ReactDOM.render(<App />, document.getElementById('root'));
  </script>
</body>

上面的例子中,点击按钮每次加 1,并不是 2,也不是 3 可以证明后面的 setState 覆盖了前边的。

  • setState 接收函数
    如果传给 setState 的是一个函数的话,那么这个函数可以拿到当前的 state。如果传了两个函数的话,那么在数据更新完后会执行第二个参数函数。
<body>
  <div id="root"></div>
  <script type="text/javascript" src="./js/react.development.js"></script>
  <script type="text/javascript" src="./js/react-dom.development.js"></script>
  <script type="text/javascript" src="./js/babel.min.js"></script>
  <script type="text/babel">
    // 类组件
    // 根组件
    class App extends React.Component {
      state = {
        count: 0
      }
      addCount = () => {
        this.setState(preState => preState.count++, () => console.log(this.state));
      }
      render() {
        return (
          <div>
            <div>
              {this.state.count}
            </div>
            <button onClick={this.addCount}>add</button>
          </div>
        );
      }
    }
    // 渲染虚拟dom
    ReactDOM.render(<App />, document.getElementById('root'));
  </script>
</body>

受控组件与非受控组件

  • 非受控组件:没有通过 state 控制的表单元素,它自己控制自身的值
  • 受控组件:表单元素的值被 React 中 state 控制,这个表单元素就是受控组件。

下面的例子中 Head 组件中 input 的值由 state.name 决定,所以它是受控组件,而 Body 组件中 input 的值由它自己决定,所以它是非受控组件。

<body>
  <div id="root"></div>
  <script type="text/javascript" src="./js/react.development.js"></script>
  <script type="text/javascript" src="./js/react-dom.development.js"></script>
  <script type="text/javascript" src="./js/babel.min.js"></script>
  <script type="text/babel">
    // 类组件
    class Head extends React.Component {
      state = {
        name: '孤城浪人',
        age: 18
      }
      changeName = () => {
        this.setState({ name: '孤城' });
      }
      render() {
        return (
          <div>
            姓名:{this.state.name}<br />
            年龄:{this.state.age}<br />
            <input type="text" value={this.state.name} />
            <button onClick={this.changeName}>changeName</button>
          </div>
        )
      }
    }
    class Body extends React.Component {
      render() {
        return (
          <div>
            <input type="text" />
          </div>
        )
      }
    }
    // 根组件
    class App extends React.Component {
      render() {
        return (
          <div>
            <Head />
          </div>
        );
      }
    }
    // 渲染虚拟dom
    ReactDOM.render(<App />, document.getElementById('root'));
  </script>
</body>

函数组件

函数组件就跟他的名字一样是一个函数,如下例子,必须要返回 UI 结构。

<body>
  <div id="root"></div>
  <script type="text/javascript" src="./js/react.development.js"></script>
  <script type="text/javascript" src="./js/react-dom.development.js"></script>
  <script type="text/javascript" src="./js/babel.min.js"></script>
  <script type="text/babel">
    // 渲染虚拟dom
    function App() {
      return (
        <div>
          我是 APP 组件
        </div>
      )
    }
    ReactDOM.render(<App />, document.getElementById('root'));
  </script>
</body>

状态

在 16.8 版本以前函数组件是没有状态的,16.8 版本推出Hooks API就使得函数组件和类组件的功能性一致了,既有状态,也有了生命周期方法。这里只简单说一下 useState 和 useEffect 两个 API。

  • useState:使用方法如下,让函数组件也有状态,注意: useState 不可以用 if…else
  • useEffect:使用方法如下,当第二个参数为[]时会在组件挂载时就会重新调用第一个参数函数,若第二个参数为[name],那么每次 name 变化时就会重新调用第一个参数函数。
function App() {
      const [ name, setName ] = useState();
      useEffect(() => {
        setName('孤城浪人');
      }, [])
      return (
        <div>
          姓名:{name}
        </div>
      )
    }

更改状态就调用就调用 useState 方法返回的第二个参数,他是一个函数,将新值作为参数调用就行了。

受控组件

因为函数组件有了状态,那么这里受控组件就和类组件的受控与非受控组件非常相似了。

我是孤城浪人,一名正在前端路上摸爬滚打的菜鸟,欢迎你的关注。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值