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

复制代码
转载请注明出处,未经同意,不可修改文章内容。

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

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

编号:[react_25]

1 "UI 组件"和"容器组件"的拆分

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

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

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

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

1️⃣在 src 目录下创建一个"UI 组件"------ TodoListUI.js

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

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

jsx 复制代码
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 组件"里:

jsx 复制代码
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 文件里有很多报错):

3️⃣打开 TodoListUI.js 文件,我们来挨着排除错误(请跟着我的编号,阅读以下 TodoList.jsTodoList.js 文件):

🔗前置知识:《React 入门------⑤ 拆分组件和组件间传值》

TodoListUI.js 文件:

jsx 复制代码
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 文件:

jsx 复制代码
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;

看看页面效果(正常运行,无报错):

2 无状态组件

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

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

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

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

  • 通过 class 生成的"类"里边会有很多"生命周期函数 "要执行, render 函数只是其中之一;
  • 通过"函数"(无状态组件)改写后,只需要执行一个函数即可。
jsx 复制代码
/*
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;

看看页面效果(正常运行,无报错):

祝好,qdywxs ♥ you!

相关推荐
辻戋1 小时前
从零实现React Scheduler调度器
前端·react.js·前端框架
徐同保1 小时前
使用yarn@4.6.0装包,项目是react+vite搭建的,项目无法启动,报错:
前端·react.js·前端框架
Qrun2 小时前
Windows11安装nvm管理node多版本
前端·vscode·react.js·ajax·npm·html5
中国lanwp2 小时前
全局 npm config 与多环境配置
前端·npm·node.js
JELEE.3 小时前
Django登录注册完整代码(图片、邮箱验证、加密)
前端·javascript·后端·python·django·bootstrap·jquery
TeleostNaCl5 小时前
解决 Chrome 无法访问网页但无痕模式下可以访问该网页 的问题
前端·网络·chrome·windows·经验分享
前端大卫6 小时前
为什么 React 中的 key 不能用索引?
前端
你的人类朋友6 小时前
【Node】手动归还主线程控制权:解决 Node.js 阻塞的一个思路
前端·后端·node.js
小李小李不讲道理8 小时前
「Ant Design 组件库探索」五:Tabs组件
前端·react.js·ant design
毕设十刻8 小时前
基于Vue的学分预警系统98k51(程序 + 源码 + 数据库 + 调试部署 + 开发环境配置),配套论文文档字数达万字以上,文末可获取,系统界面展示置于文末
前端·数据库·vue.js