简书项目课程 学习总结(复习)

3/18

环境搭建

  • 引入.js文件
  • 通过脚手架工具编码,一般有grunt/webpack/gulp帮助我们编写脚手架
  • create-react-app 官方提供的脚手架工具 可定制性强

工程目录文件简介

  • yarn.lock是我们项目依赖的安装包
  • README.md项目说明文件,可以自己用markdown重写。
  • package.json 相当于脚手架工具 或者项目的介绍,还有依赖的包,主要是node的包文件,可以让项目变成node包
  • .gitignore,里面的文件不会上传到git
  • node_modules第三方包文件
  • public目录,代码入口index.js,还有之前没有注意到的,js文件里引入css文件。react的设计思路就是all in js
  • PWA、manifest.json、自动化测试

3/19

react的代办事件例子

react帮我们完成数据和dom的映射,我们现在就是关心数据就好了,就不需要考虑dom。

?需要复习:this指向问题,比如箭头函数、bind()绑定

react中有一个概念:immutable,state不允许我们做任何改变,我们只能操作副本。不然不利于性能优化。

JSX语法细节补充

Fragment、dangerouslySetInnerhtml、htmlfor、className

拆分组件与组件的传值

父->子:在父组件里为子组件起属性名,在子组件里this.props就可以拿到父组件传过来的。

子->父:子组件不能直接修改父组件的state,但是我们可以结合利用父组件向子组件传值的方法,可以在子组件里调用父组件的方法,向子组件传递方法时,记得bind this指向。

Todolist代码优化

解构赋值把this.props拿出来;map循环可能是一大段js代码,可以封装成一个函数,在jsx里调用;

setState不用再直接填一个对象了,直接用函数return一个对象,或者用括号代替return,但是写成函数的形式时,这个setState就会变成异步的了,需要在setState外额外保存一下需要用到的state,而且这个函数有prevState,相当于this.state.

key要放在循环的最外层的标签里。

React衍生思考

  • 命令式编程:一步一步的去做,一般都是在做dom操作
  • 声明式编程:React就是
  • 还可以与其他框架并存的,index.html里面操作的不是一个div;
  • 组件式开发
  • 单向数据流,子组件只能使用父组件传过来的值(read only property),但是不可以修改它,为了测试或者调试方便,不容易留坑。万一哪个state出bug了,又不知道是哪个子组件传的,那就很麻烦了。所以还是父组件方法对应自己的属性,就更方便。
  • 视图层框架,只帮忙页面渲染和数据,组件传值交给其他组件。并不是什么都帮我们解决,我们可能需要一些数据层框架里辅助我们,比如mobx、redux
  • 函数式编程,利于自动化编程,比如给函数赋值,就可以得到结果

PropTypes与DefaultProps

要先引入,PropTypes是可以对子组件里拿到的props属性做类型校验的。可以加isRequired,还可以arrayof()/oneOfType()来实现多种类型选择。DefaultProps就是默认的值。

props、state与render函数

数据和页面互相联动的机理:当组件的state或者props发生改变的时候,render函数就会重新执行。

当父组件的render被执行的时候,子组件的render也会被执行。

什么是虚拟DOM

JSX模板+数据 生成真实的DOM,如果发生state的变化,就继续替换数据,在此生成真实的DOM,一次次DOM片段的替换,非常消耗性能。但实际上页面可能只有一部分的DOM发生改变,所以我们第二次state的改变时,我们也生成新的DOM,但是并不直接替换原始的DOM,只做比较,找出差异去替换.但是这样,性能提升仍然不明显.因为还是生成真的DOM.

那我们就改成数据+模板生成虚拟DOM,虚拟DOM就是js对象,用它描述真实DOM.如果state发生改变了,然后比较两个虚拟DOM,找到区别,直接操作DOM.

3/20

深入了解虚拟DOM

真实情况是,第一次:得到模板后,*是先生成虚拟DOM,再生成真实DOM。*比如:JSX -> createElement -> 虚拟DOM对象 -> 真实的DOM

return React.createElement('div',{},'item')

优点:

  1. 性能提升,将DOM的对比换成了JS对象的对比
  2. 它使得跨端应用得以实现,React Native,就是用react语法写原生应用。因为原生应用(安卓/ios)里没有DOM的,有了虚拟DOM就可以对比了。在原生应用里,虚拟DOM转化为原生的应用组件。在网页应用里,虚拟DOM就转化为真实的DOM。

虚拟DOM的diff算法

react会合并几次setState,所以setState是设计成异步的,为了减少虚拟DOM的比较次数。Diff算法应用于虚拟DOM的比较,比较遵循的是同层比较。比如先对比第一层,如果发现第一次的DOM都不一样了,那就不继往下层比较,而是直接删除下面的,重新生成。用重新生成的DOM替换原始页面的DOM。

算法简单,时间就快了。虚拟DOM的比较也根据key值来比较。所以我们不要简单粗暴地把index作为组件的key值,不然很难保持和新的虚拟DOM的key值保持一致了。比如删掉最前面的组件,后面的都跟着变了,会导致key值不稳定。我们可以试着用item作为key值,也就是内容。。。但是内容万一很多呢?

React中ref的使用

在react里可以用e.target获取事件的元素对应的DOM,也可以用ref。

ref = {(input) => {this.input = input}}
//拿到input标签对应的实际DOM元素
//获取dom
const value = this.input.value

然鹅,如果用它放在setState后来操作DOM,例如,this.ul.querySelector(‘div’).length的个数就总是会少一个。因为setState是异步的。所以react提供了setState的第二个参数,用来当异步执行完后再调用的回调函数

生命周期

生命周期函数是在某一个时刻会自动调用执行的函数。

react旧版生命周期包含三个过程:

1、挂载过程
constructor()
componentWillMount()
componentDidMount()

2、更新过程
componentWillReceiveProps(nextProps)
shouldComponentUpdate(nextProps,nextState)
componentWillUpdate (nextProps,nextState)
render()
componentDidUpdate(prevProps,prevState)

3、卸载过程
componentWillUnmount()

其具体作用分别为:
1、constructor() :完成了React数据的初始化(props/sate)。

2、componentWillMount() :组件已经完成初始化数据,但是还未渲染DOM时执行的逻辑,主要用于服务端渲染。在组件即将被挂载到页面的时刻自动执行。

3、componentDidMount():组件第一次渲染完成时执行的逻辑,此时DOM节点已经生成了。组件被挂载到页面上被自动执行

4、componentWillReceiveProps(nextProps):接收父组件新的props时,重新渲染组件执行的逻辑。

5、shouldComponentUpdate(nextProps, nextState):在setState以后,state发生变化,组件会进入重新渲染的流程时执行的逻辑。在这个生命周期中return false可以阻止组件的更新,主要用于性能优化。在组件更新之前,要求返回一个boolean类型结果。

6、componentWillUpdate(nextProps, nextState):shouldComponentUpdate返回true以后才执行,组件进入重新渲染的流程时执行的逻辑。

7、render():页面渲染执行的逻辑,render函数把jsx编译为函数并生成虚拟dom,然后通过其diff算法比较更新前后的新旧DOM树,并渲染更改后的节点。

8、componentDidUpdate(prevProps, prevState):组件更新完,重新渲染后执行。

9、componentWillUnmount():组件被移出、卸载前执行的逻辑,比如进行“清除组件中所有的setTimeout、setInterval等计时器”或“移除所有组件中的监听器removeEventListener”等操作。

在这里插入图片描述

react16.4后使用了新的生命周期,使用getDerivedStateFromProps代替了旧的componentWillReceiveProps(要从父组件接受参数,以及父组件的render函数重新被执行)及componentWillMount。使用getSnapshotBeforeUpdate代替了旧的componentWillUpdate。

利用生命周期提升性能或应用场景

①子组件不跟着父组件无端端被渲染:

shouldComponentUpdate(nextProps,nextState) {
	if(nextProps.content !== this.props.content) {
	return true;
	}
	return false;
}

②函数的bind绑定都放在constructor里,这样这些绑定只会执行一次。

③componentDidMount里发生Ajax请求,如果放到render里,就会造成死循环。我只需要发送一次ajax。componentWillMount什么会因为同构应用产生冲突。

使用Charles实现本地数据mock:中间代理服务器,能抓到我们的请求。

React的动画效果

三元运算符的使用,CSS3提供的过渡效果:@keyframes和animation和forwards保持最后一帧的效果。

react-transition-group:第三方库,还能拓展,用js实现动画效果

redux的入门介绍

react只是视图层的轻量级应用,它的数据管理、组件传值不行。我们可以配合数据管理层框架,redux,我们少把数据放到组件里,数据都放在store里管理,一个组件改变了store的内容,其他组件都会感知到并取到新的数据。redux = Reducer + Flux。

组件从store里拿数据,也需要改变数据。组件可以看成是图书馆借书的人,action creator就是你说的要借什么书这句话,这句话传给store,store理解为图书馆管理书的管理员,但她需要记录一下每本书的情况,这个记录本就是reducer。store通过reducer找到书,就返给组件。

组件要改变数据,也先和action说一句话,action就告诉store,store不知道怎么修改,要去查reducer如何改,reducer告诉后,store就去修改,修改好了再告诉组件,我改好了,你来拿好了。

在这里插入图片描述

用redux编写todolist

创建store

在store文件夹里创建index.js,通过createStore()创建了store数据公用空间,记得导出去。但这个store是什么都不知道的,所以要顺便把小本本(reducer.js)创建出来,reducer.js里都是函数,接受state(store里上一次存储的)和action,还可以定义defaultState。回到组件页面,store.getState()就可以拿到store的内容了。

?export default 和 export有什么区别?

Action和reducer的编写

比如我们提交按钮的时候,我们需要改变state,我们要说一句话,就是要在提交事件里写一个action对象,这个action是有一定规范的,他有type,有描述,再通过store.dispatch(action)告诉store

store知道了,但是他不知道怎么做,他就带着prevState和action去reducers里找。store很聪明,一旦他接受到action就自动去reducer里找,也就是会自动执行reducer的方法,reducer可以拿到之前存储的store和这次要干的action。reducer根据action.type去判断是做的什么事情。

JSON.parse(JSON.stringfy(state))就是深拷贝。要操作newState,再返回newState给store管理员。也叫reducer能接受state,但不能修改state。

组件页面里,store.subscribe(函数)来进行store数据更新到页面上~也就是订阅store的改变,store改变了就自动执行里头的函数。这样就实现了整个数据的流通更新啦。

actionTypes.js对action的type进行统一管理,这样写错了报错了也不会找不到错误。

使用actionCreator.js来统一管理页面所有的action。也就是把之前组件页面里写的action对象,在这个文件里写好方法,方法直接返回对应的action对象。然后组件页面引入了后直接调用方法就可以了。

3/21

redux知识点复习

  • store必须是唯一的。
  • 只有store能改变自己的内容。并不是reducer改变,reducer里不能直接写state.xxxx = ssss,他只负责生成新的数据,store拿到newState,他才进行更新。
  • reducer必须是纯函数。有固定的输入,就有固定的输出,而且不会有任何副作用。
  • redux的核心API:createStore 、store.dispatch 、store.getState、 store.subscribe

UI组件与容器组件的拆分

UI组件一般称为傻瓜组件(负责渲染),容器组件称为聪明组件(负责逻辑)。

当UI组件调用父组件的方法,且要给函数传参时:

onClick = {(index) => {this.props.handleItemDelete(index)}}

因为之前涉及到this指向问题,就是要bind(this,参数)

无状态组件

当一个普通组件只有一个render方法,那他就是一个无状态组件。这个无状态组件就是方法。无状态组件性能可以提高,无需像类一样执行额外的多余的生命周期方法。

const TodoListUI = (props) => {
retunr (
	<div></div>
)}

redux中发送异步请求

使用了axios,那怎么从store里拿呢?

首先要去actionCreators.js里创建函数,就是创建一个action对象描述这个异步请求完的事件。然后actionType也要跟进。再返回容器组件调用一下这个方法创建action,再派发给store。所以要接着写reducer

使用Redux-thunk中间件进行ajax请求发送

redux-thunk可以帮助我们把一些异步请求和复杂逻辑放到action里处理。这是redux的中间件,不是react的。

首先要在createStore的页面里引入applyMiddleware,记得会和redux-devTools冲突。然后,我们就可以在actionCreators里编写函数,且是返回函数的函数,以前仅仅只能返回一个描述action的对象,不然dispatch()里会报错,说action只能是对象。!然后如果要改变store里的数据,就又要走redux的流程,这里面也可以disptach!

什么是Redux中间件

redux中间件就是对Dispatch方法的封装和生级。根据参数不同执行不同的流程。

Redux-sage中间件的使用

同样也是异步处理的中间件。可以去GitHub上学习配置。sagas.js里的函数必须是generator函数。takeEvery方法接受action,然后执行自己编写的方法。就是相当于reducer捕获action一样。我们也可以实现异步逻辑拆分到saga.js文件里。然后用put代替store.dispatch,去给到store,store再去查看reducer里换取内容。

React-Redux的使用

第三方模块,帮助我们更好地用redux。

熟悉地组件!用它来包裹起来。提供器连接了store,包裹起来的内部所有组件都能获取store里的内容了。

怎么获取呢? 第二个核心API:connect。它能帮助组件和store做连接。第一个参数是把store的数据映射成Props给组件,所以组件得改写成this.props.xx调用公共数据里写的state,这些state是在reducer里的defaultState里定义的。第二个参数是如果要对store的内容要做修改,把store.dispatch的方法挂载到props上。

connect(mapStateToProps,mapDisPatchToProps)(组件名称)
const mapStateToProps = (state) =>{
	return {
		inputValue: state.inputValue
	}
}
const mapDispatchToProps = (dispatch) => {
	return {
		changeInputValue(e) {
		const action = {
			type: 'change',
			value:e.target.value
		}
			dispatch(action)//派发到store,再给reducer
		}
	}
}

通过connect,可以实现数据变,页面就跟着变化了。connect返回的内容实际上运行导出的结果是一个容器组件,因为它负责逻辑部分,它对UI组件进行包装。

简书PC项目所有命令

create-react-app jianshu
yarn add styled-components

文件夹介绍

  • common文件夹:公用组件(header)
  • statics文件夹:放置静态资源文件
  • index.js是项目入口

injectGlobal问题

injectGlobal这个API 从现在开始废除了,换成 createGlobalStyle 新的API ,作为一个样式组件出现,按照样式组件思想,以一个标签形式被引入。

参考:https://blog.csdn.net/weixin_42614080/article/details/106037806

图片当background问题

由于webpack打包的时候,background的属性值会当作字符串,所以需要在开头import的形式,然后使用多行文本嵌入变量的形式 background: url(${logoPic}) 去完成效果。

3/27

使用redux-react-dev,会报错:说reducers不是函数,因为也就是说,保证传入createStore的reducer要是一个函数,createStore的第三个参数,enhancer,也要是一个函数。原因是我忘记加()了。compose就是一个包装函数。安装好后工具就变绿了~。

3/31

使用combineReducers

不能把数据都放在reducers,不然太庞大了,管理员(store)会翻看得很慢。可以先找分类,再去找具体操作。分类方法是,在自己得组件里管理数据。比如在自己组件的文件里建立一个store文件夹。同时查看Redux管理工具,看state也帮忙把数据分层了。

然鹅,初步整理好后,动画效果木有了~原因是mapStateToProps里的state要加个header,才能成功取到数据,才能根据focus来加动画效果。

所以,我们把大reducer拆分成许多小reducer,通过combineReducers做整合。而且目录路径记得也整理一下。

使用actionCreators

刚开始我们这样写action的

handleInputBlur() {
      const action = {
        type: "search_blur",
      };
      dispatch(action);
 },

但是我们不建议把action直接写成对象,或者action的type写成常量比较好。我们在对应的组件里的store文件夹里编写actionCreator.js,在里面定义:不过为啥({})就是定义对象了?

export const searchFocus = () => ({
    type: 'search_focus'
})

//组件文件夹
import  * as actionCreators  from "./store/actionCreator";
handleInputBlur() {
       const action = actionCreators.searchBlur()
      dispatch(action);
    },

还有就是把actionType变成常量,在各个文件夹里做修改~

store文件夹里的index.js都要利用好,做一个出口。

引入immutable.js来管理store中的数据

reducer拿action和原始state做处理,返回新的state,但是我们不能直接修改state,但是immutable.js库就可以帮助我们实现。是Facebook开发的库,帮我们生成immutable的对象,假设state是一个immutable的对象,我们写代码就不会不小心出错。

所以我们一旦把state对象换成immutbale对象,就需要做各种修改,因为普通对象的一些使用方法已经不适用于immutable对象了。

yarn add immutable

//reducer文件
import {fromJS} from 'immutable'  //把js对象转化成immutable对象

const defaultState = {
    focused: false, //输入框是否被选中
};
//👇👇
const defaultState = fromJS({
    focused: false //输入框是否被选中
});

const mapStateToProps = (state) => {
  return {
    focused: state.header.focused,
  };
};
//👇👇使用get方法
focused: state.header.get('focused')


if(action.type === constants.SEARCH_BLUR) {
        return {
            focused:false
        }
}
    //👇👇使用set方法
 if(action.type === constants.SEARCH_BLUR) {
        return state.set('focused',false);
  }

immediate对象的set方法会结合之前的immutable对象的值和设置的值,返回一个全新的对象。

4/1

完善immutable

const mapStateToProps = (state) => {
  return {
    focused: state.header.get('focused')
  };
};

要把这个state也从js对象改成immutable对象,首先看看大reducer对象,这里是定义和整合大state的文件。

yarn add redux-immutable

//交换
import {combineReducers} from 'redux';
import {combineReducers} from 'redux-immutable';

//修改
focused: state.header.get('focused')
 focused: state.get('header').get('focused')
 //等价于
 focused: state.getIn(['header','focused'])

SearchInfo组件开发

这节课老师有讲到怎么查看元素的样式欸~~

Ajax获取请求热门搜索数据

ctrl+D就可以选择所有相同关键字了~

只需要在第一次聚焦输入框时发送Ajax请求,然后在react里保存好数据,后面都不需要再次请求了。其次呢,我们说异步函数不要写在组件里,我们可以借助redux-thunk写在action里头~redux-thunk可以看作是action和store之间的一个中间件,那么我们去到创建store的store.js文件夹里面引入redux-thunk。

在public里建立一个api文件夹,放一些json文件,然后用地址栏去访问是可以访问到这些数据的,是create-react-app的一个惊喜吧。因为它的底层是node服务器,它会现到工程目录找路由,找不到就去public里看看有没有对应的路径,因此我们可以在public写假数据。

隐含难搞的细节:

 if(action.type === constants.CHANGE_LIST) {
        return state.set('list',action.data);
    }

看似正确,实则不正确,因为list是被转为immutable类型的数组,但是传过来的data又是普通数组对象,所以呢,我们需要在写异步函数那里(actionCreator.js)里通过fromJS()做一些处理。

4/3

代码优化

由于switch里的case语句已经弄了return了,所以不需要break了。

实现换一换功能

增添两个页码page和totalPage的数据,来实现换一换的功能。

首先for循环完成page的算法,第一页显示0~9的数据。

for(let i = (page-1)*10; i<page*10;i++){
      pageList.push(//html)
}

其次,要让热门搜索的框框点击不失焦。所以不能用focused来控制了,要多加一个属性mouseIn属性,然后用redux的流程去写就好辣~

onClick={handleChangePage}传参的时候,需要把它变成箭头函数,在箭头函数里执行,才能带参数。why?

key失效问题

   <SearchInfoItem key={newList[i]}>{newList[i]}</SearchInfoItem>

因为header组件渲染的时候,已经把for循环给循环十遍了~~不过刚开始循环,list的初始数据是[],所以newList也是空数组,所以每一项都是undefinded。所以需要判断一下newlist是不是空数组,我们只要Ajax请求后的数据。

spin图标的旋转

利用ref节点拿到dom,用dom节点操作style样式,去做spin的图案的旋转。

ref={(icon)=>{this.spinIcon = icon}}

妙啊妙啊,又用到正则表达式,又用js代码操作样式

let originAngle = spin.style.transform.replace(/[^0-9]/ig,'');//让spin图案旋转360度
      if(originAngle){
        originAngle = parseInt(originAngle,10)
      } else {
        originAngle = 0;
      }
      spin.style.transform =  'rotate(' +(originAngle + 360)+ 'deg)'

这次动画效果不用react提供的组件了,直接用css里的transition过渡效果。

很重要一句话:react面向数据编程,最难的地方是reducer的数据如何设计!react要遵循redux单向数据流的流程。

如何规避不必要的Ajax请求

热门搜索的内容只需要聚焦第一次,获取一次就足够了。做法就是把数据list这个state作为参数传递给handleInputFocus方法,你会发现第二次请求list这个对象的size属性会变成50。

(list.size === 0) && dispatch(actionCreators.getList());

4/5

首页开发,路由的使用

yarn add react-router-dom
import { BrowserRouter , Route } from 'react-router-dom'

要是报错说:只能有一个children,那就是在最外层多添加一个div/fragment标签就好了。

?为啥我在reducer.js里都没给reducer起名字,都可以在大reducer里随便起名引入尽力嘚?

!!redux插件里的state真的可以好好看一看,太好玩了!太清晰了!

home组件又开始写reducer

4/7

首页异步请求

在home的index.js里,借助componentDidMount来发送Ajax请求。

在home组件里,我dispatch呢,并不是只有大reducer接受到,只有小reducer才接受到。

然后home组件是个UI组件,里面不适合放请求—》而mapDispatch才是容器组件,可以把逻辑函数部分放入mapDispatch里。----》当然我们用了redux-thunk,应该放在redux-thunk里。所以我们可以进一步在home的store里通过actionCreators创建action。

欸?为啥actionCreators里派发一次action,到了home组件页面又要派发一次action?答案:第一次派发,为了触发actionCreator,第二次派发,为了修改数据。不过我觉得有点点麻烦~如果数据流不多的话,但是这也的逻辑一定要懂。

4/10

加载更多的功能

分析该组件放在哪里,其实它和文章列表是一体的,可以放到文章列表List组件里头~然后为它添加异步点击事件。我们再加一个数据接口,将拿到的数据拼接在数组后。

初步写完异步流程,会报错:× TypeError: item.get is not a function。也就是说,这个数据不是一个immutable数据,所以使用get方法会无效。根据redux调试工具,发现state里的articleList的数据请求得不对,一看,我请求的地址错了。

虽然页面的数据请求成功了,但是打开控制台,还是有错误,因为我们重复请求同一批数据,key值就会因重复报错。暂时用上index去代替。

进阶的是,真实生活和场景中,我们加载更多是利用分页来完成的。我们告诉后端这是第几页,然后后端再根据页码去拿,所以我们可以再请求地址上带上页码的参数:

 axios.get("/api/homeList.json?page=" + page).then()

然后,派发action的时候手动给页码加1,并在reducer接受到action,更新state里去,这样就能动态自增页码数辣~

  dispatch(addHomeList(result, page + 1))

回到顶部的功能

在index里写了,定义一个state去判断它是否在最顶部了,不是才显示返回顶部,通过监听scroll事件,判断离顶部的距离,然后派发action去修改这个state,组件页面会根据这个state的true/false来选择是否展示返回顶部的组件。在组件被销毁的时候,记得把window这个全局绑定的监听给移出了,remove~~

首页代码调优和路由跳转

我们每个组件都通过connect和store数据池做了连接,所以只要store的数据改变一点点,每个组件的render都会被重新执行,都会被重新渲染。

第一个解决办法就是在每个组件里写shouldComponentUpdate,去判断是否需要更新本组件。由于我用了immutable管理数据,所以可以用上react fiber提供的一个新的内置组件——PureComponent。

页面跳转方面,不得不提的是我们用react写的网页希望是单页面应用,也就是路由跳转的时候只请求一次html文件,像我们之前用的a标签去做链接跳转,每一次跳转都会请求一次html文件,很耗费性能。所以我们用Link代替a。

顺带把首页的图标也改为Link请求,所以要把组件a改为div:

export const Logo = styled.a.attrs({
    href: '/'
})`

查看是否有请求HTML文件:控制台-network-docs

突然明白为何要两次派发action了,第一次是在组件里派发action,这个被创建出来的action是去做异步请求的,然后这个action再把请求拿到的数据去做第二次派发,给reducer。我们dispatch action的时候,是所有reducer都能接受到的。

详情页传参

第一种方式是动态路由的方式,然后this.props里的match里就会有params。

  <Link to="/detailed">
  ↓👇↓
  <Link to={"/detailed" + item.get("id")}>
  <Route
            path="/detailed:id"
            component={Detail}
            exact
  />
  componentDidMount() {
      this.props.getDetail(this.props.match.params.id);
  }

第二种方式是直接在请求地址里放上参数,统样可以在this.props里找到,但是拿到的是?id=1这种形式,需要自己去处理一下。

  <Link to={"/detailed?id" + item.get("id")}>
  <Route
            path="/detailed"
            component={Detail}
            exact
 />

登录功能

首先把登录页面写好了然后去实现首页检测是否登录。传递两个input的真实dom,这样就可以拿到styled-component组件的value值了~

 <Input placeholder="用户名" ref={(input) => {this.account = input}}/>
             <Input placeholder="密码" type="password" ref={(input) => {this.password = input}}/>
             <Button onClick={()=> this.props.login(this.account,this.password)}>登录</Button>

退出登录的时候,要在header组件里拿login文件夹下的actionCreators去修改login的值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值