前端 react 面试题

1.react介绍

  1. React 是Facebook内部的一个JavaScript类库。
  2. React 可用于创建Web用户交互界面。
  3. React不是一个完整的MVC框架,最多可以认为是MVC中的V(View),甚至React并不非常认可 MVC开发模式。
  4. React 的设计思想极其独特,属于革命性创新,性能出众,代码逻辑却非常简单。
  5. React 引入了虚拟DOM(Virtual DOM)的机制。
  6. React 引入了组件化的思想。
  7. React 使用Facebook专门为其开发的一套语法糖–JSX。

2.特点

虚拟DOM 组件化 JSX语法

3.优缺点

优点:

  1. 组件化开发 ​
  2. 引入虚拟DOM,性能好,响应速度快 ​
  3. JSX语法
  4. 单向数据绑定 Data Flow ​
  5. 跨浏览器兼容 ​
  6. 完善的生态圈和活跃的社区

缺点:

  1. 不是完整MVC框架 ​
  2. 不适用于复杂的大型应用

4.脚手架安装

npm i create-react-app -g  //安装react脚手架
create-react-app demo //创建项目
cd demo //进入项目
npm start //启动项目 http://localhost:3000

目录结构:

-demo
-src
index.js 入口文件
App.js 根组件
index.css 样式
App.css App组件的样式

注意:

  1. 如果你保存就报错,删掉js-css-html formate插件

  2. 如何在vscode直接写标签

    首先在 设置->emmet ->setting.json

"emmet.includeLanguages": {
        "javascript":"javascriptreact"
    },

5.JSX介绍

非表单元素绑定数据 属性绑定:{}

1.JSX语法遇到 < 就按HTML语法解析,遇到{ 就按JavaScript语法解析
2.使用三元表达式
3.使用函数表达式
4.JSX 标签可以相互嵌套
5.注意换行和缩进,增强代码的可读性,建议使用小括号括上 JSX 代码,防止分号自动插入的bug
6.属性绑定
7.style属性的值必须是一个对象
8.绑定class类名,必须使用className,不能使用class
9.注释 {/注释/}

6.列表渲染

Key可以在DOM中的某些元素被增加或删除的时候帮助React识别哪些元素发生了变化。
因此你应当给数组中的每一个元素赋予一个确定的标识。
一个元素的key最好是这个元素在列表中拥有的一个独一无二的字符串。
通常,我们使用来自数据的id作为元素的key。

7.事件绑定

import React, { Component } from 'react';
import './App.css';
// 事件怎么绑定->参数传递—>event—>阻止默认事件 阻止事件传播—>当前这个框架有没有自己的事件小知识

class App extends Component {
  a = 10;//属性
  fn() {//方法
    alert(this.a)
  }
  alertN(m,n){
    alert(m+n);
  }
  getEvent(e){
    console.log(e)
    console.log(e.clientX)
  }
  getEvent2(e,n){
    console.log(e.clientX)
    console.log(n)
  }
  cancelRightKeyDown(e){
    e.preventDefault();   
    console.log("右键了")
    // return false;
  }
  outerClick(){
    console.log("outer click")
  }
  innerClick(e){
    e.stopPropagation();
    console.log("inner click")
  }

  outerClick2(e){
    e.stopPropagation()
    console.log("outer2 click")
  }
  innerClick2(e){
    console.log("inner2 click")
  }


  render() {//渲染
    var b = 20;
    return (
      <div>
        <h1>this is app</h1>
        <p>{this.a}</p>
        <p>{b}</p>
        {/* 1.事件绑定方式 ①箭头函数 ②bind */}
        <button onClick={()=>this.fn()}>点击就执行fn--1</button>
        <button onClick={this.fn.bind(this)}>点击就执行fn--2</button>

        {/* 2.事件传参 */}
        {/* ①箭头函数 直接书写你的参数 */}
        {/* ②bind 第一个参数是调用该函数的对象,从第二个参数开始,才是你要传递的参数 */}
        <button onClick={()=>this.alertN(3,5)}>3+5</button>
        <button onClick={this.alertN.bind(this,10,20)}>10+20</button>

        {/* 3.event */}
        {/* ①箭头函数 显示传参 在箭头函数的形参就是event ,event 可以在任何位置*/}
        {/* ②bind 隐式传参 最后一个参数就是event */}
        <button onClick={(ev)=>this.getEvent(ev)}>event1</button>
        <button onClick={this.getEvent.bind(this)}>event2</button>

        <button onClick={(e)=>this.getEvent2(e,10)}>e,10</button>
        <button onClick={this.getEvent2.bind(this,20)}>e,20</button>

        {/* 4.阻止默认事件 */}
        {/* 注意:只能通过e.preventDefault阻止,在react中,return false不行 */}
        <div className="box" onContextMenu={(e)=>this.cancelRightKeyDown(e)}>box1</div>
        <div className="box" onContextMenu={this.cancelRightKeyDown.bind(this)}>222</div>

        {/* 5.阻止事件传播 */}
        {/* e.stopPropagation() */}
        <div className="outer" onClick={()=>this.outerClick()}>
          <div className="inner" onClick={(e)=>this.innerClick(e)}></div>
        </div>

        {/* <div className="outer" onClick={this.outerClick.bind(this)}>
          <div className="inner" onClick={this.innerClick.bind(this)}></div>
        </div> */}

        {/* 6.如果想要绑定是捕获,那么就在你的事件后面加Capture */}

        <div className="outer" onClickCapture={this.outerClick2.bind(this)}>
          <div className="inner" onClickCapture={this.innerClick2.bind(this)}></div>
        </div>
        
      </div>
    )
  }
}

export default App;

7.组件注册

1.函数定义

//函数定义组件
import React from "react"
function Hello(){
    return (
        <div>
            <h1>this is hello</h1>
        </div>
    )
}
export default Hello;

2.类定义

//类组件
import React,{Component} from "react"
class First extends Component {
    render(){
        return (
            <div>
                <h1>this is First</h1>
            </div>
        )
    }
}
export default First

注意:

1.组件名称 首字母必须大写
2.组件的模板必须只能有 一个根节点

对比两种定义方式

1.函数定义没有生命周期 类定义的组件有生命周期,比如render constructor;
2.函数定义接收父组件传递的数据用props,类定义接收父组件传递的数据使用的是this.props;
3.类定义有state状态机,当调用setState,会重新执行render,函数定义是没有state.

8.父传子

{/* 父传子:父组件通过自定义属性传递,子组件通过props接收。
      如果子组件是函数定义,就使用props;
      如果子组件是类定义,就使用this.props */}
      <Hello d={appData} a={10}></Hello>
      <First d={appData}></First>

9.React解决了什么问题?

组件化:这是react的核心
开发效率:react代码基本就是组件的组合,只用关心一个render函数,不用关心视图局部的修改
运行效率:react实现了虚拟dom,相比于其他框架具有更优的效率
可维护性:react基于flux或者redux的架构设计,确定的store很容易定位问题

10.React、vue、angular有什么区别?

答案:
开发者 数据绑定 依赖标准 渲染页面 模式
vue 尤雨溪 双向数据绑定 ES5/es6 模板+脚本+样式 MVVM
react FaceBook 单向数据绑定 es6 JSX 不是MVVM
angular 谷歌 双向数据绑定 typescript 模板 MVC(1)/MVVM(2…)

11.react diff 原理?

当你使用react的时候,在某个时间点render函数创建了一颗react元素树,在下一个state或者props更新的时候,react函数将创建一颗新的react树,react将对比两棵树的不同之处,计算出如何高效的更新UI(值更新变化的地方)

12.JSX是什么?浏览器怎么解析JSX?

JSX 将 HTML 语法直接加入到 JavaScript 代码中,再通过翻译器转换到纯 JavaScript 后由浏览器执行。
浏览器中通过给script标签添加type="text/bable"属性来解析jsx

13.props

1.函数定义的组件接收props用props. 如果该组件接收的props发生了发生了改变,会重新渲染。
2.类定义组件接收props用this.props。如果该组件props或者state发生了改变,会重新渲染。
3.在构造函数里面调用super(props)?
super() 目的是为了在constructor里面使用this
super(props) 目的是为了在constructor里面使用this.props

constructor(props){ 
        //super() 目的是为了在constructor里面使用this
        //super(props) 目的是为了在constructor里面使用this.props 
        super(props)
        console.log(this.props)
    }

14.state

1.只有类定义的组件才有state
2.setState()会触发render执行
3.取值

const {num,a}=this.state;

4.操作state里面的arr或者json,需要先取出,然后做你的逻辑操作,再通过setState赋值回去

 		changeName(name) {
        var { json } = this.state;
        json.name = name;
        this.setState({
            json
        })
    }

5.setState()是异步的,如果你想要操作后的值再进行操作,那么需要写到回调函数里面
6…render里面调用setState会陷入死循环,所以千万不要这样做。
7.setState会造成页面不必要的渲染,所以state里面的状态应该是页面使用的数据最小集合。

15.组件交互

注意:子组件接收父组件的值,子组件不能修改。
父传子
父组件通过自定义属性传递,子组件通过props接收.如果子组件是函数定义,就通过props,如果子组件是类定义,就通过this.props.

​ parent.js

<Child d={data}></Child>

Child.js (函数定义)

<div>{props.d}</div>

子传父

​ 父组件通过自定义属性传递,子组件通过props接收。如果子组件是函数定义,就通过props,如果子组件是类定义,就通过this.props.

​ parent.js

 <Child data={d} onChildClick={this.changeD.bind(this)}></Child>
 <Child2 data={d} child2Click={(e)=>this.changeD(e)}></Child2>

Child.js 类定义

import React, { Component } from 'react'

export default class Child extends Component {
    render() {
        const { data,onChildClick } = this.props;
        return (
            <div className="box">
                <h3>this is child</h3>
                <p>父组件传递的数据:{this.props.data}</p>
                <p>data:{data}</p>
                <button onClick={this.props.onChildClick.bind(this,'child change')}>点击就修改父组件的d,改为”child change"</button>
                <button onClick={()=>this.props.onChildClick('111')}>点击修改父组件d:'1111'</button>
                <button onClick={()=>onChildClick('222')}>222</button>
            </div>
        )
    }
}

​ Child2.js 函数定义

import React from 'react';
function Child2(props) {
    const { data, child2Click } = props;
    return (
        <div className="box">
            <h3>this is child 2</h3>
            <p>data:{props.data}</p>
            <p>data:{data}</p>
            <button onClick={props.child2Click.bind(null, '333')}>333</button>
            <button onClick={() => child2Click("444")}>444</button>
        </div>
    )
}
export default Child2;

注意:在子传父的自定义属性传参,父组件接收通过event.react中没有全局组件。

16.(组件的)状态(state)和属性(props)之间有何不同?

答案:state是一种数据结构,用于组件挂载时定义数据的默认值。修改state使用setState,会触发render函数执行,渲染页面。
props是由父组件传递给子组件的。对于子组件而言,props是不可变的。

17.类组件(Class component)和函数式组件(Functional component)之间有何不同?

答案:函数组件无state和生命周期,传值需要用props
类组件有state和生命周期,传值需要this.props

18.为什么建议传递给 setState 的参数是一个 callback 而不是一个对象?

答案:因为this.setState的更新是异步的。

19.(在构造函数中)调用 super(props) 的目的是什么?

答案:在super被调用之前,子类是不能使用this的,在ES5中,子类必须在constructor中调用super().
传递props给super()的原因则是便于子类能在constructor中访问this.props

20.ref

1.字符串

<div ref="box">123</div>
this.refs.box.offsetLeft

2.React.createRef()

constructor(){
  super()
  this.el=React.createRef()
}
<div ref={this.el}>45654</div>


aa(){
  this.el.current.offsetLeft; //..
}

3.ref回调函数

//此回调函数回自动执行,currentNode参数为当前节点,每次更新(初始化不算)执行两次,第一次参数为null,第二次参数为当前节点,但这不影响任何
<input ref={(currentNode)=>{this.input1=currentNode}}/>

//获取值
this.input1.value

vue:

<div ref="div">
  123
</div>
this.$refs.div.offsetLeft

//parent.vue 
<Child ref="child"></Child>
this.$refs.child.aa()

//child.vue
export default{
	methods:{
	aa(){

	}
}
}

场景:

1.处理焦点、文本选择或媒体控制
​ 2.触发强制动画
​ 3.集成第三方 DOM 库
​ 注意,当组件挂载完毕,即componentDidMount,我们才能通过this.refs调用到以上元素.

21. 音频

audio.play();//播放
audio.pause();//暂停
audio.οntimeupdate=()=>{
audio.currentTime //当前播放时间 单位是s
audio.duration //歌曲总时长 单位是 s
}
audio.currentTime=100;//音频调到100s
audio.currentTime+=10;//快进10s
audio.muted=true|false;
audio.volume=0.5;//改变声音 [0,1]

22.react中使用stylus

1.安装依赖包

npm i stylus stylus-loader --save

2.npm run eject

如果成功了,那就恭喜你!

如果失败了,怎么解决?

1.先安装一个git,然后安装。官网 傻瓜式安装
2.如果你的电脑是mac,那么打开终端就可以了,进入你的项目文件夹;
如果你的电脑是windows,那么就在你的项目文件夹里面 右键->git hash here,点击它。
3.git add .  //添加所有文件
	如果问了你一句话:who you are?
	git config --global user.name "hlt"
	git config --global user.email '11@qq.com'
	git add .
4.git commit -m "13243" //提交

5.再次执行 npm run eject

找到你的webpack配置文件(config/webpack.config.js),搜索"oneOf",

{
    test: /\.styl$/,
    use: [
        require.resolve('style-loader'),
        require.resolve('css-loader'),
        require.resolve('stylus-loader')
    ]
},

23.react 生命周期函数?

1.类定义组件才有生命周期

3个阶段

初始期 :只执行一次

1.constructor 创建 初始化数据,也是初始化state的生命周期
2.componentWillMount 挂载之前 渲染之前可以修改你的数据
3.render 渲染 渲染dom节点,在更新的时候,做的是:进行diff算法,更新dom元素
4.componentDidMount 挂载完成 ajax 开启计时器 操作DOM节点

更新期: props或者state变了,都会进行更新 ,可以执行很多次

componentWillReceiveProps(nextProps)
接收的props发生了改变
shouldComponentUpdate (nextProps,nextState)
1.不书写这个生命周期,那么你的生命周期执行顺序:componentWillUpdate->render->componentDidUpdate
2.书写了这个生命周期
没有return ,那么就报错
return true,那么你的生命周期顺序:shouldComponentUpdate->componentWillUpdate- >render->componentDidUpdate
return false,那么你的生命周期执行顺序:shouldComponentUpdate
componentWillUpdate 将要更新
render 渲染 进行diff算法,更新dom元素
componentDidUpdate 更新完成

销毁期

componentWillUnmount 销毁之前 做善后工作
如果开启过计时器,订阅,异步请求 都要取消,否则就会报错。

24.shouldComponentUpdate 是做什么的?

第一个 不存在 数据正常更新 。
第二个 存在 数据被拦截
按照你自己的需求去返回true 或者false,这个函数存在必须要返回相关的布尔值, 否则报错 。
①如果是true的时候
生命周期的顺序是
shouldComponentUpdate是否要更新-》componentWillUpdate将要更新=》 render渲染-》componentDidUpdate更新
②如果是false 就结束了
只走了shouldComponentUpdate-----是否要更新

25.为什么虚拟 dom 会提高性能?

虚拟DOM其实就是一个JavaScript对象。通过这个JavaScript对象来描述真实DOM。
为什么用虚拟dom?真实DOM的操作,一般都会对某块元素的整体重新渲染。
采用虚拟DOM的话,当数据变化的时候,只需要局部刷新变化的位置就好了。

26.应该在 React 组件的何处发起 Ajax 请求?

componentDidMount

27.在 React 中,refs 的作用是什么?

Refs 是 React 提供给我们的安全访问 DOM 元素或者某个组件实例的句柄。
我们可以为元素添加 ref 属性然后在回调函数中接受该元素在 DOM 树中的句柄,
该值会作为回调函数的第一个参数返回。
用于对 render() 返回的特定元素或组件的引用。
当需要进行 DOM 测量或向组件添加方法时,它们会派上用场。

28.使用箭头函数(arrow functions)的优点是什么?

作用域安全:在箭头函数之前,每一个新创建的函数都有定义自身的 this 值,但箭头函数不会,它会使用封闭执行上下文的 this 值。
简单:箭头函数易于阅读和书写
清晰:当一切都是一个箭头函数,任何常规函数都可以立即用于定义作用域。

29.路由

1.基础路由

npm i react-router-dom --save

​ 引入 index.js

// 1. 引入路由模式 BrowserRouter |HashRouter
import {BrowserRouter} from "react-router-dom"

//2.嵌套根组件
ReactDOM.render(<BrowserRouter><App /></BrowserRouter>, document.getElementById('root'));

​ 路由出口 (router-view)

import React, { Component } from 'react'
import {Switch,Route} from "react-router-dom"
import Login from "./pages/Login/Login"
import Index from "./pages/Index/index"

export default class App extends Component {
  render() {
    return (
      <div>
        <Switch>
          <Route path="/login" component={Login}></Route>
          <Route path="/index" component={Index}></Route>
        </Switch>
      </div>
    )
  }
}

​ 路由跳转(router-link [active-class])

import {Link,NavLink} from "react-router-dom"
 <Link to="/index">首页</Link>
 <NavLink to="/index">首页2</NavLink>

<NavLink activeClassName="select" to="/index/man">男装</NavLink>
<NavLink activeClassName="select" to="/index/women">女装</NavLink>
<NavLink activeClassName="select" to="/index/child">童装</NavLink>

​ 路由基本配置规则 ({path:"/login",component:login})

 <Route path="/login" component={Login}></Route>

​ 路由重定向 (redirect)

import {Switch,Route,Redirect} from "react-router-dom"	
				<Switch>
          <Route path="/login" component={Login}></Route>
          <Route path="/index" component={Index}></Route>
          <Redirect to="/login"></Redirect>
        </Switch>

如果你使用路由的时候,报了Redirect的错误,建议你把node_modules删掉,在cmd里面安装 npm i

2.嵌套路由

 								<Switch>
                    <Route path="/index/man" component={Man}></Route>
                    <Route path="/index/women" component={Women}></Route>
                    <Route path="/index/child" component={Child}></Route>
                </Switch>

3.编程式导航

​ vue

this.$router.push()
this.$router.replace()
this.$router.go(-1)

react

this.props.history.push("/movie") //添加一条新的历史记录
this.props.history.replace("/food")//替换当前历史记录
this.props.history.go(-1)//返回

使用前提是:该组件是参与路由的组件,就可以直接使用上面的编程式导航。

如果某个组件不是参与路由的组件,那么你需要引入withRouter方法解决。

import React, { Component } from 'react'
import {withRouter} from "react-router-dom"
class Back extends Component {
    goBack(){
        this.props.history.go(-1)
    }
    render() {
        return (
            <button onClick={this.goBack.bind(this)}>封装的返回组件</button>
        )
    }
}
export default withRouter(Back)

4.传参

​ vue

? this.$route.query
: this.$route.params

react

如果是通过? 传参 ,参数在 this.props.location.search ,需要自己手动解析为键值对
第一种方式:

var str=this.props.location.search.slice(1);//'foodId=22&a=10&b=20'
        var arr=str.split("&");//["foodId=22", "a=10", "b=20"]
        var json={};
        arr.forEach(item=>{
            var tempArr=item.split("=");//["foodId","22"]
            json[tempArr[0]]=tempArr[1]
        })
        console.log(json)//做你的逻辑操作

第二种方式:

import querystring from "querystring"
var json=querystring.parse(this.props.location.search.slice(1))

如果通过 动态路由 传参 ,那么参数在this.props.match.params

30.路由拦截

在登录成功的时候,做一个标识。

 					//存一个标识,用来做登录拦截判断
            localStorage.setItem("name",user.name)

定义了一个组件,MyRoute ,哪些组件需要做登录拦截,就用MyRoute定义他的路由规则

<MyRoute path="/movie" component={Movie}></MyRoute>
<MyRoute path="/movie-detail/:id" component={MovieDetail}></MyRoute>
<MyRoute path="/food" component={Food}></MyRoute>
<MyRoute path="/food-detail" component={FoodDetail}></MyRoute>

MyRoute组件内容

import React, { Component } from 'react'
import Login from "../Login/Login"
import {Route} from "react-router-dom"
export default class MyRoute extends Component {
    componentWillMount(){
        this.name=localStorage.getItem("name");//如果没有登录,name-null 如果登陆了,name-admin
    }
    render() {
        return (
            <div>
               {
                   this.name?<Route {...this.props}></Route>:<Login></Login>
               } 
            </div>
        )
    }
}

Login.js 用withRouter调用。

31.懒加载

Util/asyncComponent.js

import React,{Component} from "react"
function asyncComponent(fn){
    class AsyncComponent extends Component {
        constructor(){
            super();
            this.state={
                c:null
            }
        }
        componentDidMount(){
            fn().then(mod=>{
                this.setState({
                    c:mod.default
                })
            })
        }
        render(){
            var C=this.state.c;
            return (
                <div>
                    {
                        this.state.c?<C></C>:null
                    }
                </div>
            )
        }
    }
    return AsyncComponent;
}
export default asyncComponent;

注意:带有参数组件 不要用

32.为什么需要react中的路由

答案:Router 用于定义多个路由,当用户定义特定的 URL 时,
如果此 URL 与 Router 内定义的任何 “路由” 的路径匹配,
则用户将重定向到该特定路由。所以基本上我们需要在自己的应用中添加一个 Router 库,
允许创建多个路由,每个路由都会向我们提供一个独特的视图

33.react router和常规路由有何不同?

答案:
​ 参与的页面:
​ reactRouter:只涉及单个HTML页面;
​ 常规路由:每个视图对应一个新文件。
​ URL更改:
​ reactRouter:仅更改历史记录属性
​ 常规路由:http请求被发送到服务器并且接收相应的html页面
​ 体验:
​ reactRouter:用户认为自己正在不同的页面间切换
​ 常规路由:用户实际在每个视图的不同页面切换

34.axios

安装

npm i axios --save 

配置代理(记得重启)

//package.json
{
  "proxy":"http://localhost:3000"
}

发起数据请求

//get 
axios({
  url:'url',
  method:"get",
  params:{}
}).then(res=>{})

//post
axios({
  url:"url",
  method:"post",
  data:{}
}).then(res=>{})

如果上班post传参,后端收不到,那么就使用qs模块。

npm i qs --save 
import qs from "qs"

axios({
  url:"url",
  method:"post",
  data:qs.stringify({})
}).then(res=>{})

拦截

//请求拦截
axios.interceptors.request.use(config=>{
  console.log(config);
  config.token="12244353545645643545756"
  return config;
})
//响应拦截
axios.interceptors.response.use(res=>{
  console.log(res);
  return res;
})

35.antd?是什么?如何安装和使用?

antd是基于 Ant Design 设计体系的 React UI 组件库,主要用于研发企业级中后台产品。
安装:npm install antd --save
使用:import { DatePicker } from ‘antd’;

36.当你调用setState的时候,发生了什么事?

当调用 setState 时,React会做的第一件事情是将传递给 setState 的对象合并到组件的当前状态。这将启动一个称为和解的过程。和解的最终目标是以最有效的方式,根据这个新的状态来更新UI。 为此,React将构建一个新的 React 元素树(您可以将其视为 UI 的对象表示)。
一旦有了这个树,为了弄清 UI 如何响应新的状态而改变,React 会将这个新树与上一个元素树相比较( diff )。
通过这样做, React 将会知道发生的确切变化,并且通过了解发生什么变化,只需在绝对必要的情况下进行更新即可最小化 UI 的占用空间。

37.在 React 当中 Element 和 Component 有何区别?

一个 React element 描述了你想在屏幕上看到什么。换个说法就是,一个 React element 是一些 UI 的对象表示。
一个 React Component 是一个函数或一个类,它可以接受输入并返回一个 React element

38.React中路由有哪些常用组件?说明它们的作用?

BrowserRouter,在需要使用路由的页面中引入;
Switch,路由选择器
Route,路由配置规则
Redirect,路由重定向
Link,路由导航
NavLink,带activeClass的路由导航

39.redux(一部分,需详细学习)

Redux 是 JavaScript 状态容器,提供可预测化的状态管理.

.1.单一数据源
    整个应用状态,都应该被存储在单一store的对象树中。
2.只读状态
    唯一可以修改状态的方式,就是发送(dispatch)一个动作(Action),通俗来讲,就是说只有getter,没有setter。
3.使用纯函数去修改状态,

组件 ————》react-redux《——————redux---- ———》Redux-thunk《—————————后台

Redux state 状态

​ reducer(action) 修改状态 (约定 注册任务)

​ dispatch(action) 派发任务 同步

Redux-thunk 中间件 异步操作

1.安装redux react-redux

npm i redux react-redux --save

2.创建仓库 store/index.js

//1.安装 npm i redux --save
import {createStore} from "redux"

//2.初始化数据 state
const initialState = {
    name: "妲己",
    age: 20,
    num:1,//数字
}


//action creator 
//修改name的action
export const changeNameAction=(name)=>({
    type:"changeName",
    username:name
})
//num++ action
export const addAction=()=>({
    type:"add"
})
//num-- action
export const subAction=()=>({
    type:"sub"
})



//3.reducer 注册任务 action={type:"动作名称",}
//注意:reducer return的内容是下一次的状态。
function reducer(state = initialState, action) {
    switch (action.type) {
        case "changeName":
            //{type:"changeName",name:"王昭君"}
            return {
                ...state,
                name: action.username
            }
        case "add":
            //{type:"add"}
            return {
                ...state,
                num:state.num+1
            }
        case "sub":
            //{type:"sub"}
            return {
                ...state,
                num:state.num-1
            }
        default:
            return state;
    }
}
//4.创建仓库
const store=createStore(reducer);

//5.reselect---getters 

//导出name
export var getName=()=>store.getState().name;
//导出age
export var getAge=()=>store.getState().age;
//导出num
export var getNum=()=>store.getState().num;


//6.导出
export default store;

3.使用react-redux 关联react 和redux

入口文件 index.js

import {Provider} from "react-redux"
import store from "./store"
ReactDOM.render(<Provider store={store}><App /></Provider>, document.getElementById('root'));

4.将需要状态管理层数据的组件改写为容器型组件

		import {connect} from "react-redux"
    class A extends Component{

        render(){
            const {name,changeName}=this.props;
            return (
                <div></div>
            )
        }
    }
    const mapStateToProps=()=>{
        return {
            name:getName(),
            //...
        }
    }
    const mapDispatchToProps=(dispatch)=>{
        return {
            changeName:(name)=>dispatch(changeNameAction(name)),
            //...
        }
    }
    export default connect(mapStateToProps,mapDispatchToProps)(A)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值