(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!

相关推荐
崔庆才丨静觅3 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60614 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了4 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅4 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅4 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅5 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment5 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅5 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊5 小时前
jwt介绍
前端
爱敲代码的小鱼5 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax