likes
comments
collection
share

(25)Redux 进阶——① UI 组件、容器组件和无状态组件 | React 基础理论实操

作者站长头像
站长
· 阅读数 7
转载请注明出处,未经同意,不可修改文章内容。

🔥🔥🔥“前端一万小时”两大明星专栏——“从零基础到轻松就业”、“前端面试刷题”,已于本月大改版,合二为一,干货满满,欢迎点击公众号菜单栏各模块了解。

涉及面试题:
1. 什么是无状态组件?
2. 什么是有状态组件?
3. React Redux 中展示组件和容器组件之间的区别是什么?
4. 组件和不同类型?

编号:[react_25]

1 “UI 组件”和“容器组件”的拆分

紧接上篇代码,请自行打开 TodoList.js 文件。

这个组件里边包含了很多内容,但在实际代码编写过程中,这种把“如何渲染”和“逻辑执行”放在一起的编码方式,会给后期代码维护造成很大的不便。

故,我们需要对这个组件进行拆分:

  • 让“UI 组件”专门做组件的“渲染”;
  • 让“容器组件”去处理组件的逻辑。

1️⃣在 src 目录下创建一个“UI 组件”—— TodoListUI.js(25)Redux 进阶——① UI 组件、容器组件和无状态组件 | React 基础理论实操

2️⃣参照之前所学,编写“UI 组件”的相应代码(先将 TodoList.js 文件里关于“页面渲染”的代码,全部剪切并粘贴至“UI 组件”):

先打开 TodoList.js 文件,剪切里边“页面渲染”相关的代码:

import React, {Component} from "react";
import 'antd/dist/antd.css';

import { Input, Button, List } from 'antd';  

import store from "./store";

import {getInputChangeAction, getAddItemAction, getDeleteItemAction} from "./store/actionCreators"; 

import TodoListUI from "./TodoListUI"; /*
																			 2️⃣-②:从当前目录下的 TodoList.js 文件中,
																			 引入 TodoListUI 组件;
                                        */

class TodoList extends Component {
  constructor(props) {
    super(props);
    
    this.state = store.getState();
    
    this.handleInputChange = this.handleInputChange.bind(this);  
    
    this.handleStoreChange = this.handleStoreChange.bind(this);  
    
    this.handleButtonClick = this.handleButtonClick.bind(this); 
    
    store.subscribe(this.handleStoreChange);  
    
  }
  
  render() {
    return <TodoListUI /> /*
    											2️⃣-③:直接返回“UI 组件”。
    											即,页面具体要显示什么,由“UI 组件”决定;
                           */
    
    /*
    2️⃣-①:先将这部分与“渲染页面”有关的代码剪切;
    (
      <div style={{marginTop: "10px", marginLeft: "10px"}}>
        <div>
          <Input 
            value={this.state.inputValue} 
            placeholder="todo info" 
            style={{width: "300px", marginRight: "10px"}} 
            
            onChange={this.handleInputChange}  
          /> 
          
          <Button type="primary" onClick={this.handleButtonClick}>提交</Button>  

          <List style={{marginTop: "10px", width: "300px"}} 

            bordered
            dataSource={this.state.list}
            renderItem={(item, index) => <List.Item onClick = {this.handleItemDelete.bind(this, index)}>{item}</List.Item>}
          />  
          
        </div>
      </div> 
    )
     */
    
  }
  
  
  handleInputChange(e) { 

    const action = getInputChangeAction(e.target.value)
    
    store.dispatch(action);  
  }

  handleStoreChange() { 
    
    this.setState(store.getState()); 
  }


  handleButtonClick() { 
    
    const action = getAddItemAction();  
    
    store.dispatch(action); 
  }

  handleItemDelete(index) { 

    const action = getDeleteItemAction(index);
    
    store.dispatch(action); 
  } 

}

export default TodoList;

打开 TodoListUI.js 文件,将 2️⃣-① 中剪切的部分,粘贴到这个“UI 组件”里:

import React, {Component} from "react";

class TodoListUI extends Component {

  render() { // 2️⃣-④:将 TodoList 里关于“页面渲染”的代码,全部剪切并粘贴至此;
  	return(  
    	<div style={{marginTop: "10px", marginLeft: "10px"}}>
        <div>
          <Input 
            value={this.state.inputValue} 
            placeholder="todo info" 
            style={{width: "300px", marginRight: "10px"}} 
            
            onChange={this.handleInputChange}  
          /> 
          
          <Button type="primary" onClick={this.handleButtonClick}>提交</Button>  

          <List style={{marginTop: "10px", width: "300px"}} 

            bordered
            dataSource={this.state.list}
            renderItem={(item, index) => <List.Item onClick = {this.handleItemDelete.bind(this, index)}>{item}</List.Item>}
          />  
          
        </div>
      </div>
    )
  }
}

export default TodoListUI;

看下页面效果( TodoList.js 文件里有很多报错): (25)Redux 进阶——① UI 组件、容器组件和无状态组件 | React 基础理论实操

3️⃣打开 TodoListUI.js 文件,我们来挨着排除错误(请跟着我的编号,阅读以下 TodoList.jsTodoList.js 文件): 🔗前置知识:《React 入门——⑤ 拆分组件和组件间传值》

TodoListUI.js 文件:

import React, {Component} from "react";

// 3️⃣-③:并粘贴至“UI 组件”里;
import { Input, Button, List } from 'antd';  

class TodoListUI extends Component {

  render() {  
    return(  
      <div style={{marginTop: "10px", marginLeft: "10px"}}>
        <div>
      
          {/*
           3️⃣-①:Input 标签是从 Antd Design 引入的,
           故需要在这个组件中引入,而不是在 TodoList 组件中引入;
            */}
						
					  {/*
             3️⃣-④:对于 value 值,在“UI 组件”中,它是没有 state 的,
             state 是 TodoList 组件里的。故,需要“组件间传值”的方式,取得这个 state;
						 value={this.state.inputValue}
						  */}
						{/* 3️⃣-⑥:“UI 组件”接收 TodoList 组件传过来的值; */}		
            
						{/* 
             3️⃣-⑦:同理,handleInputChange 函数是在 TodoList 组件里定义的,
             也需要通过“属性”的形式传递过来;
             onChange={this.handleInputChange} 
              */}
            {/* 3️⃣-⑨:“UI 组件”接收 TodoList 组件传过来的值; */}

          <Input  
						
						value={this.props.inputValue}

            placeholder="todo info" 
            style={{width: "300px", marginRight: "10px"}} 
            
            onChange={this.props.handleInputChange}
          /> 
          
              
          {/*
           3️⃣-⑩:同理,handleButtonClick 也需要从 TodoList 中传过来;
           <Button type="primary" onClick={this.handleButtonClick}>提交</Button> 
            */}
          {/* 3️⃣-⑫:“UI 组件”接收 TodoList 组件传过来的值; */}
          <Button type="primary" onClick={this.props.handleButtonClick}>提交</Button>


            {/*
             3️⃣-⑬:同理,state 也需要从 TodoList 中传过来;
             dataSource={this.state.list}
              */}
            {/* 3️⃣-⑮:“UI 组件”接收 TodoList 组件传过来的值; */}

						{/*
             3️⃣-⑯:同理,handleItemDelete 也需要从 TodoList 中传过来;
             renderItem={(item, index) => <List.Item onClick = {this.handleItemDelete.bind(this, index)}>{item}</List.Item>}
              */}
            {/*
             3️⃣-⑲:“UI 组件”接收 TodoList 组件传过来的值(
             ❗️请注意我 index 是怎样用“箭头函数”传进去的);
              */}
          <List 
						style={{marginTop: "10px", width: "300px"}} 
            bordered
            
            dataSource={this.props.list}

            renderItem={(item, index) => (<List.Item onClick = {() => {this.props.handleItemDelete(index)}}>{item}</List.Item>)}

          />  
          
        </div>
      </div>
    )
  }
}

export default TodoListUI;

TodoList.js 文件:

import React, {Component} from "react";
import 'antd/dist/antd.css';

/*
3️⃣-②:把 Antd Design 关于“页面渲染”的内容剪切;
import { Input, Button, List } from 'antd';  
 */

import store from "./store";
import {getInputChangeAction, getAddItemAction, getDeleteItemAction} from "./store/actionCreators"; 

import TodoListUI from "./TodoListUI"; 


class TodoList extends Component {
  constructor(props) {
    super(props);
    
    this.state = store.getState();
    
    this.handleInputChange = this.handleInputChange.bind(this);  
    
    this.handleStoreChange = this.handleStoreChange.bind(this);  
    
    this.handleButtonClick = this.handleButtonClick.bind(this); 
    
    // 3️⃣-⑱:在这里对 handleItemDelete 方法的 this 指向作一个修改;
    this.handleItemDelete = this.handleItemDelete.bind(this);
    
    store.subscribe(this.handleStoreChange);  
    
  }
  
  render() {
    return(
      
      /*
      3️⃣-⑤、3️⃣-⑧、3️⃣-⑪、3️⃣-⑭、3️⃣-⑰:
      通过“属性”的形式传值给 TodoListUI 组件;
       */
      <TodoListUI
        inputValue={this.state.inputValue}
        list={this.state.list}  
        handleInputChange={this.handleInputChange}
        handleButtonClick={this.handleButtonClick}
        handleItemDelete={this.handleItemDelete}
      />
    )
  }
  
  
  handleInputChange(e) { 

    const action = getInputChangeAction(e.target.value)
    
    store.dispatch(action);  
  }

  handleStoreChange() { 
    
    this.setState(store.getState()); 
  }


  handleButtonClick() { 
    
    const action = getAddItemAction();  
    
    store.dispatch(action); 
  }

  handleItemDelete(index) { 

    const action = getDeleteItemAction(index);
    
    store.dispatch(action); 
  } 

}

export default TodoList;

看看页面效果(正常运行,无报错): (25)Redux 进阶——① UI 组件、容器组件和无状态组件 | React 基础理论实操

2 无状态组件

紧接上边的代码,打开 TodoListUI.js 文件,这里边我们把 TodoListUI 定义成了一个“”。

但,实际编码中,当我们去定义一个“UI 组件”的时候,如果这个组件只负责“页面渲染”(即,只有一个 render 函数),且没有其他任何逻辑操作时,我们一般直接用“无状态组件”来定义“UI 组件”。

“无状态组件”可以简单理解为一个“函数”。

之所以要用“函数”来改写,是为了“提高性能”:

  • 通过 class 生成的“类”里边会有很多“生命周期函数”要执行, render 函数只是其中之一;
  • 通过“函数”(无状态组件)改写后,只需要执行一个函数即可。
/*
2️⃣-④:由于这里没用到 Component,故删掉!
import React, {Component} from "react";  
 */
import React from "react"; 

import { Input, Button, List } from 'antd';  

// 2️⃣然后改写成一个函数;
const TodoListUI = (props) => { // 2️⃣-①:这个函数会接收一个“参数”props;
  return(
    // 2️⃣-②:然后返回一段 JSX;
    // 2️⃣-③:❗️注意用 props 替换 this.props。
    <div style={{marginTop: "10px", marginLeft: "10px"}}>
      <div>
        <Input  
          
          value={props.inputValue}

          placeholder="todo info" 
          style={{width: "300px", marginRight: "10px"}} 
          
          onChange={props.handleInputChange}
        /> 
        
        <Button type="primary" onClick={props.handleButtonClick}>提交</Button>

        <List 
          style={{marginTop: "10px", width: "300px"}} 
          bordered
          
          dataSource={props.list}

          renderItem={(item, index) => (<List.Item onClick = {() => {props.handleItemDelete(index)}}>{item}</List.Item>)}

        />  
        
      </div>
    </div>
  )
}

/*
1️⃣直接将以下代码全部删除;
class TodoListUI extends Component {

  render() {  
    return(  
      <div style={{marginTop: "10px", marginLeft: "10px"}}>
        <div>
          <Input  
            
            value={this.props.inputValue}

            placeholder="todo info" 
            style={{width: "300px", marginRight: "10px"}} 
            
            onChange={this.props.handleInputChange}
          /> 
          
          <Button type="primary" onClick={this.props.handleButtonClick}>提交</Button>

          <List 
            style={{marginTop: "10px", width: "300px"}} 
            bordered
            
            dataSource={this.props.list}

            renderItem={(item, index) => (<List.Item onClick = {() => {this.props.handleItemDelete(index)}}>{item}</List.Item>)}

          />  
          
        </div>
      </div>
    )
  }
}
 */


export default TodoListUI;

看看页面效果(正常运行,无报错): (25)Redux 进阶——① UI 组件、容器组件和无状态组件 | React 基础理论实操

祝好,qdywxs ♥ you!

转载自:https://juejin.cn/post/7305938219694342163
评论
请登录