【React】react组件传参、redux状态管理
- 一、props:父组件向子组件传参
- 1、将普通的参数作为props传递
- 2、将jsx作为props传递(组件插槽)
- (1)基础功能示例
- (2)进阶示例
- 二、自定义事件:子父组件向父组件传参
- 三、context进行多级组件传参
- 四、redux全局状态管理
- 1、redux概述
- 2、redux的组成
- 1.1 State-状态
- 1.2 Action-事件
- 1.3 Reducer
- 1.4 Store
- 3、redux入门案例
- 1.1 前期准备
- 1.2 构建store
- 1.2.1 在src下新建redux文件夹
- 1.2.2 在redux文件夹下新建store.js文件
- 1.2.3 在store.js文件里编写redux核心代码
- 1.2.4 在redux文件夹下新建reducers.js文件
- 1.2.5 在store.js文件中引入reducers.js
- 1.2.6 到根目录下的index.js文件导入store仓储对象
一、props:父组件向子组件传参
- 所有props是单向的,对于子组件来说,父组件传过来的数据都是只读的,所有不要尝试做修改
1、将普通的参数作为props传递
function Child(props: { name: String }) {
const { name } = props;
return (
<div style={{border:'1px solid'}}>
<h3>我的子页面</h3>
{name}
</div>
);
}
function App() {
return (
<div>
<h2>标题:父组件向子组件传参</h2>
<Child name={"我是父组件传过来的参数"} />
</div>
);
}
2、将jsx作为props传递(组件插槽)
- 父组件可以向子组件传递一些普通的值以外,还可以传递以下jsx,那这就不得不提到插槽的概念,如以下代码,就是利用jsx语法实现了所谓的一个插槽的概念
(1)基础功能示例
function List(props:{children:any}) {
//children会接受父元素开始和结束标签之间的内容
const {children}=props
return <div>{children}</div>;
}
function App() {
return (
<div>
<List>
<li>列表项1</li>
<li>列表项1</li>
<li>列表项1</li>
</List>
<List>
<li>列表项2</li>
<li>列表项3</li>
<li>列表项3</li>
</List>
</div>
);
}
(2)进阶示例
- 向多个位置传递jsx
function List(props: any) {
//title,footer如果是可选的注意要设置默认值
//如果不设置的话或包语法错误,我这里title是必选
const { children, title, footer = <div>默认底部</div> } = props;
return (
<>
<h2>{title}</h2>
<ul>{children}</ul>
<div>{footer}</div>
</>
);
}
function App() {
// 优化:这里应该将下面的列表处理成一个数组包含对象的形式进行map渲染
return (
<div>
<List title="列表1" footer={<p>底部1</p>}>
<li>列表项1</li>
<li>列表项1</li>
<li>列表项1</li>
</List>
<List title="列表2">
<li>列表项2</li>
<li>列表项2</li>
<li>列表项2</li>
</List>
</div>
);
}
二、自定义事件:子父组件向父组件传参
- 通过父组件给子组件设置自定义事件,然后通过事件触发向父组件传递参数;
function Detail(props: any) {
const { onActive } = props;
//status为控制Detail的内容显示不显示
const [status, setStatus] = useState(false);
function handClick() {
setStatus(!status);
//将参数status传给父组件
onActive(status);
}
return (
<>
<button onClick={handClick}>按钮</button>
<p style={{ display: status ? "block" : "none" }}>Detail的内容</p>
</>
);
}
function App() {
function handActive(status: any) {
// status就是子组件传过来的参数
console.log(status);
}
return (
<div>
{/* 给子组件绑定一个自定义事件onActive */}
<Detail onActive={handActive} />
</div>
);
}
三、context进行多级组件传参
import { createContext,useContext } from 'react';
createContext
:在任意组件外调用 createContext 创建一个上下文,createContext 返回一个上下文对象
useContext
: 是一个 React Hook,可以让你读取和订阅组件中的 context。
import React, {useContext,createContext } from 'react';
//创建 context对象
//createContext 参数 可以进行初始化操作
const MyContext= createContext(null);
//Child子组件
//const 公共数据 = useContext(Context) 这里的公共数据就是根组件value的值
function Child() {
const color = useContext(MyContext);
return <div>
<h3>我的子页面</h3>
颜色值是:{color}
<hr />
<Child1 />
</div>
}
//Child1子子组件
//const 公共数据 = useContext(Context) 这里的公共数据就是根组件value的值
function Child1() {
const color = useContext(MyContext);
return <div>
<h3>我的子子页面</h3>
颜色值是:{color}
</div>
}
function App() {
return (
// value={ 这里放要传递的数据 }
<MyContext.Provider value={"yellow"}>
<div>
<h2>useContext</h2>
<Child />
</div>
</MyContext.Provider>
)
}
export default App;
结论:
- Child和Child1都拿到了”yellow“
useContext
会在context值变化时重新渲染,<MyContext.Provider>的value发生变化时,包裹着的子组件无论是否使用value值,都会重新渲染。
可以使用memo对未使用value的子组件进行优化,在组件更新的时候memo会检测自身包裹的组件是否有数据更新,如果没有,就会阻止自身组件的重新渲染,减少性能损耗。
四、redux全局状态管理
1、redux概述
- redux是一个JavaScript容器,用于进行全局的状态管理;
- redux三大核心;
-
单一数据源头:所有state都会被挂载到一个叫Object tree中,Object tree又只存在唯一的Store(理解为容器,存储Object tree,Object tree挂在state)中;
-
State是只读的:唯一改变state的方法就是触发
action
,触发action,store.dispatch ( {type: 'COMPLETE_TODO' , index: 1})
-
使用纯函数来执行修改:编写
reducers
,接受state和action,并返回一个新的state;
-
2、redux的组成
1.1 State-状态
- 就是我们传递的数据,后端返回的数据、决定ui展示的状态等等;
1.2 Action-事件
- Action是把数据从应用传到store的载体(对象),它是store数据的唯一来源,一般来说,我们可以通过store.dispatch()将action传递给store;
- Action的特点
- Action的本质就是一个javaScript的普通对象;
- Action对象内部必须要有一个type属性来表示要执行的动作多数情况下,这个type会被定义成字符串常量;
- 除了type字段之外,action的结构随意进行定义;
- 而我们在项目中,更多的喜欢用action创建函数(就是创建action的地方);
- 只是描述了有事情要发生,并没有描述如何去更新state;
// Action创建函数
function addAction(params){
//返回一个Action对象
return {
type:'add',//add为自定义
...params
}
}
1.3 Reducer
- Reducer本质就是一个函数,它用来响应发送过来的actions,然后经过处理,把 state发送给Store的;
- 在Reducer函数中,需要return返回值,这样Store才能接收到数据;
- 函数会接收两个参数,第一个参数是初始化 state,第二个参数是action;
const initState={...}
function reducer(state=initState,action){
return {...}
}
1.4 Store
//构建store
import { createstore } from "redux";
//构建store对象
const store = createstore(传递reducer) ;
- Store 就是把action 与reducer联系到一起的对象;
- 主要职责:
- 维持应用的state
- 提供getState()方法获取state
- 提供dispatch()方法发送action
- 通过subscribe()来注册监听
- 通过subscribe()返回值来注销监听
3、redux入门案例
1.1 前期准备
- 打开VSCode终端
- 新建项目,输入npx create-react-app + 项目名称(自定义,注意最好不要中文)
- 删除多余的配置文件,只留下(App.css,App.js,index.js)并清除三个文件下不必要的代码
- 进入新的项目文件夹
- 安装redux相关依赖
npm i react-redux
npm i redux
- npm run start启动项目
1.2 构建store
1.2.1 在src下新建redux文件夹
1.2.2 在redux文件夹下新建store.js文件
1.2.3 在store.js文件里编写redux核心代码
//创建一个仓储对象,需要reducer作为对象
import { createStore} from 'redux'
1.2.4 在redux文件夹下新建reducers.js文件
const initData=[{
id:1,
name:'奔驰',
ctime: "2020-09-09'.
}];
// state是状态数据的原始值,action={type : "add " ,data:{}
function brands(state=initData,action){
switch(action.type){
//!!!!不能操作修改旧的数据
//新增品牌:不能直接修改老的状态数据,应该根据老的状态数据,生成一个新的状态数据,然后返回
case 'add_brand' :
return [ ...state].push(action.data);
//删除品牌
case 'del_brand':
const newArr=state.filter(item=>item.id!=data);
return newArr;
//修改
case 'update_brand ' :
//获取
default:
return state;
}
}
export default brands
1.2.5 在store.js文件中引入reducers.js
//创建一个仓储对象,需要reducer作为对象
import {createStore }from ' redux';
import brands from './reducers ';
const store=createStore(brands);
export default store;
1.2.6 到根目录下的index.js文件导入store仓储对象
- 导入store仓储对象
import store from "./redux/store";
打印仓储对象内容如下
- 将仓储对象传递给根组件
<App store={store}/>
等等我,等会补充更新