react学习(二)(react生命周期,父子组件传参,context,router,reactHook,redux)
生命周期
import React from "react"; class LifeCycle extends React.Component{ //React.StrictMode会让声明周期执行两次 constructor(props){ super(props) this.state={ count:1 } console.log('生命周期constructor') //初始化state,绑定this } componentDidMount(){ //渲染完成之后执行 console.log('生命周期componentDidMount') //发送网络请求 } componentDidUpdate(){ //更新之后执行 console.log('生命周期componentDidUpdate') } shouldComponentUpdate(){ //false render就不执行了(阻止渲染) console.log('生命周期shouldComponentUpdate') return true } componentWillUnmount(){ //销毁之前执行 console.log('生命周期componentWillUnmount') } handleClick=()=>{ this.setState({ count:this.state.count+1 }) } render(){ //渲染执行还没渲染完 console.log('生命周期render') return( <div> 生命周期:{this.state.count} <button onClick={this.handleClick}>点击</button> </div> ) } } export default LifeCycle
父子组件传参
函数组件
<IsPorps age={20}></IsPorps>
import React from "react"; import PropTypes from 'prop-types' function IsPorps(props) { return ( <div> {props.age} {console.log(props)} </div> ) } IsPorps.propTypes = { age: PropTypes.number //number类型,传string报警告(arry/boll/func/number/object/string) } IsPorps.defaultProps = { pageSize: 10 //默认值设置 } export default IsPorps
class组件
<PropsDiv name={'jerry'} age={20} getChild={this.getChild}> 我是子节点(类似于插槽) </PropsDiv>
import React from "react"; class PropsDiv extends React.Component { constructor(props) { //super()是用来继承,不写就用this super(props)//constructor中必须要传props,不然拿不到 console.log(this.props.name) } setParent = () => { this.props.getChild() } render() { return ( <div> <p> class子组件接收参数 : {this.props.name}---{this.props.age}</p> <button onClick={this.setParent}>点击传递数据给父组件</button> <p>{this.props.children}</p> </div> ) } } export default PropsDiv
Context 是什么?
Context 提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法。在一个典型的 React 应用中,数据是通过 props 属性自上而下(由父及子)进行传递的,但这种做法对于某些类型的属性而言是极其繁琐的(例如:地区偏好,UI 主题),这些属性是应用程序中许多组件都需要的。Context 提供了一种在组件之间共享此类值的方式,而不必显式地通过组件树的逐层传递 props。
AppContext
import React from "react"; const AppContext=React.createContext(); export default AppContext
App
import AppContext from './components/AppContext'//context多层嵌套父组件传给子组件 坑:(必须用同一个声明的AppContext,不能两个文件声明两次) <AppContext.Provider value={'多层嵌套父组件传给子组件'}> <PropsDiv name={'jerry'} age={20} getChild={this.getChild}> 我是子节点(类似于插槽) </PropsDiv> </AppContext.Provider>
ContextDiv
import React, { useContext } from "react"; import AppContext from './AppContext' //三种接收方法 //第一种AppContext.Consumer // function ContextDiv() { // return ( // <div> // Consumer: // <AppContext.Consumer>{data => <span>{data}</span> }</AppContext.Consumer> // </div> // ) // } //第二种contextType // class ContextDiv extends React.Component{ // static contextType=AppContext // render(){ // return ( // <div> // Consumer:{this.context} // </div> // ) // } // } //第三种useContext function ContextDiv() { var value=useContext(AppContext) return ( <div> Consumer:{value} </div> ) } export default ContextDiv
PropsDiv
import React from "react"; import ContextDiv from "./ContextDiv"; class PropsDiv extends React.Component { constructor(props) { //super()是用来继承,不写就用this super(props)//constructor中必须要传props,不然拿不到 console.log(this.props.name) } setParent = () => { this.props.getChild() } render() { return ( <div> <p> class子组件接收参数 : {this.props.name}---{this.props.age}</p> <button onClick={this.setParent}>点击传递数据给父组件</button> <p>{this.props.children}</p> <ContextDiv></ContextDiv> </div> ) } } export default PropsDiv
路由
import { BrowserRouter as Router, Routes, Route, Link } from "react-router-dom";
import HomeRouter from './components/HomeRouter';
import HistoryRouter from './components/HistoryRouter';
<Router> <Link to='/home'>路由点击去HomeRouter页面</Link> <br /> <Link to='/history'>路由点击去historyRouter页面</Link> <Routes> <Route path='/home' element={<HomeRouter></HomeRouter>}></Route> <Route path='/history' element={<HistoryRouter></HistoryRouter>}></Route> </Routes> </Router>
import React from "react"; class HomeRouter extends React.Component{ render(){ return( <div>HomeRouter页面:高版本中Switch已经被换成了Routes</div> ) } } export default HomeRouter
import React from "react"; class HistoryRouter extends React.Component{ render(){ return( <div>HistoryRouter页面:222</div> ) } } export default HistoryRouter
reactHook
Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
Hook 是一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数。Hook 不能在 class 组件中使用 —— 这使得你不使用 class 也能使用 React。
useState
import React, { useState } from "react"; function StateHook() { //必须在最顶层声明 const [count, setcount] = useState(1)//第一个参数就是状态,第二个参数就是改变状态方法 const [list]=useState([{id:1,name:'tom'},{id:2,name:'jerry'}]) function handleClick() { setcount(count+1) } return ( <div> <p>{count}</p> {list.map(item=> <p key={item.id}>{item.name}</p> )} <button onClick={handleClick}>点击</button> </div> ) } export default StateHook
useEffect
import React, { useState, useEffect } from "react"; function StateHook() { const [count, setcount] = useState(1)//必须在最顶层声明 // let [timer] = useState(null) function handleClick() { setcount(count + 1) } // function setDate(){ // timer = setInterval(function () { // console.log(new Date()) // }, 2000) // } useEffect(() => { //useEffect代替三个生命周期函数componentDidMount/componentDidUpdate/componentWillUnmount console.log('useEffect代替生命周期函数') //第二个参数传[],只代表componentDidMoun钩子函数,可以在这里调用接口,[count]这里传count就会监听count值变化才会执行 }, []) useEffect(() => { //useEffect代替三个生命周期函数componentDidMount/componentDidUpdate/componentWillUnmount console.log('useEffect代替生命周期函数2222') //可以创建多个useEffect // setDate() //清除副作用,不会重复执行多个定时器 // return () => { // clearInterval(timer) // } }) return ( <div> <p>{count}</p> <button onClick={handleClick}>点击</button> </div> ) } export default StateHook
ReduxHook
import React from "react"; import {useSelector,useDispatch} from 'react-redux' function ReduxHook() { //必须在最顶层声明,读取数据 const value = useSelector((state)=>{ console.log(state) return state.value }) //写入数据 const disPatch=useDispatch() function sendAction(){ disPatch({ type:'send_add', value:'useDispatch传递数据' }) } return ( <div> <p>useSelector读取redux数据:{value}</p> <button onClick={sendAction}>useDispatch传递数据</button> </div> ) } export default ReduxHook
redux
- redux是一个独立专门用于做状态管理的JS库(不是react插件库)
- 它可以用在react、angular、vue等项目中,但基本与react配合使用
- 作用:集中式管理react应用中多个组件共享的状态
- redux的结构层次:
1 store:唯一,只有一颗状态树
2 resucers:有state,只读的,通过纯函数修改
3 component:显示与事件的触发
4 action:动作派发
- getState 获取状态
- dispatch 派发动作
- subscribe 订阅事件
store/index
import { legacy_createStore as createStore } from "redux"; import { rootReducer } from "./reducer"; const store = createStore(rootReducer) export default store
store/action
const sendAction=()=>{ return { type:'send_type' } } const sendActionAdd=()=>{ return { type:'send_add' } } module.exports ={ sendAction, sendActionAdd }
store/reducer
const initState = { value: '默认值' } const rootReducer = (state = initState, action) => { console.log(state, action) switch (action.type) { case 'send_type': return Object.assign({}, state, action) case 'send_add': return Object.assign({}, state, action) default: return state } } module.exports = { rootReducer }
import React from 'react'; import store from './store'; import { Provider } from 'react-redux'; import ConnetDiv from './components/ConnectDiv'; class App extends React.Component { handleAction = () => { //发送action console.log(store.getState()) store.dispatch({ type: 'send_type', value: 'redux传值' }) } componentDidMount() { //监听 store.subscribe(() => { console.log('监听subscribe', store.getState()) this.setState({}) }) } render() { return ( <Provider store={store}> <h1>redux:</h1> <button onClick={this.handleAction}>点击发送action给reducer</button> <p>{store.getState().value}</p> <h1>react-redux:</h1> <ConnetDiv></ConnetDiv> </Provider> ); } } export default App;
import React from "react"; import { connect } from 'react-redux' class ConnetDiv extends React.Component { handleClick=()=>{ console.log(this.props) this.props.sendActionAdd() } componentDidMount(){ this.setState({}) } render() { return ( <div> <p>react-redux:</p> <button onClick={this.handleClick}>发送数据</button> <p>接受数据显示:{console.log(this.props)}{this.props.value.value}</p> </div> ) } } const mapStateToProps=(state)=>{ return{ value:state } } const mapDispatchToProps=(dispatch)=>{ return{ sendActionAdd:()=>{ dispatch({ type:'send_add', value:'connect传值' }) } } } export default connect(mapStateToProps, mapDispatchToProps)(ConnetDiv)