环境搭建
- 创建脚手架 工具
npx create-react-app my-app
cd my-app
npm start
问题
1 缺少 this.state 报错
每个constructor 必须赋值 this.state
2 对传值的 state 的进行类型检测
https://zh-hans.reactjs.org/docs/typechecking-with-proptypes.html#gatsby-focus-wrapper
3 props render states 的更新
- 当组件的state 或 props 变化时, render函数就会被重新执行
- 父组件的render 执行时,子组件的render 也将重新执行(因为父组件render时 有组件)
4 ref 用法
import React, { Component, Fragment} from 'react';
class Todolist extends Component {
constructor(props) {
super(props);
this.state = {
inputValue: ''
}
}
render () {
return (
<Fragment>
<div>
<input type="text" onChange={this.handleChange}
ref={(input) => { this.input = input}}/>
</div>
</Fragment>
)
}
handleChange (event) {
this.setState({inputValue: this.input.value})
// 注:this.setstate 是异步的,再用ref时,最好卸载 this.setstate的回调里
//this.setState({}, () => {
// console.log('sdsssssss')
// })
}
}
export default Todolist
__
https://www.jianshu.com/p/41deb68b26ed
5 生命周期函数
// 组件被更新之前调用, turn false 终止下面函数执行,return true才继续render函数
shouldComponentUpdate() { }
// 组件更新之前,shouldComponentUpdate 之后执行(必须返回true才执行)
componentWillUpdate() { }
// 页面挂载之前执行, 只执行一次
componentWillMount() {}
// 页面挂载执行,执行多次 state 改变render 执行
render() {}
// 页面挂载之后执行, 只执行一次
componentDidMount() {}
// 组件更新之后,shouldComponentUpdate 之后执行(必须返回true才执行),componentWillUpdate 之后, render函数之后,
componentDidUpdate() { }
// 从父组件接受了参数,并且父组件的render 函数 `重新` 被执行了就会被执行
componentWillReceiveProps() { }
// 组件即将被注销时,执行
componentWillUnmount() { }
生命周期函数
- 请求接口 可以放在 componentDidMount componentWillMount 或 constructor , 不过建议放在 componentDidMount 中
6 优化子组件
- 如果父组件数据发生变化,不管对子组件是否有影响,子组件都会重新渲染
- 可以通过 shouldComponentUpdate 进行优化
import React, { Component} from 'react';
class TodolistItem extends Component {
constructor(props) {
super(props);
this.state = {}
}
render () {
console.log(',,,,')
return (
<li onClick={this.handleClick}>
{this.props.content}
</li>
)
}
// props 参数发生变化才更新dom
shouldComponentUpdate (nextProps, nextState) {
// nextProps 将要传的 props nextState 将要更改的 states
return nextProps.content !== this.props.content ? true : false
}
}
};
7 过度属性
npm install react-transition-group --save
import React, { Component, Fragment} from 'react';
import './app.css'
import { CSSTransition } from 'react-transition-group';
class App extends Component {
constructor (props) {
super(props);
this.state= {
show: true
}
this.toggleFunc = this.toggleFunc.bind(this); // 函数中要用 this.setstate, 要更改指针
}
render () {
return (
<Fragment>
{/* <div className={this.state.show ? 'show' : 'hide'}>hello world</div> */}
<CSSTransition
in={this.state.show}
timeout={1000}
classNames="fade"
unmountOnExit
onEnter={(el) => {el.style.color = 'red'}}
>
<div>hello world</div>
</CSSTransition>
<button onClick={this.toggleFunc}>toggle</button>
</Fragment>
)
}
toggleFunc () {
this.setState({
show: this.state.show ? false : true
})
}
}
export default App;
/* 进场前一刻的动画 */
.fade-enter, .fade-appear {
opacity: 0;
}
/* 进场后到动画执行完的过程之间的动画 */
.fade-enter-active, .fade-appear-active {
opacity: 1;
transition: opacity 1s ease-in;
}
/* 动画执行完程样式 */
.fade-enter-done {
opacity: 1;
}
/* 出场前一刻的动画 */
.fade-exit {
opacity: 1;
}
/* 出场到动画执行完的过程之间的动画 */
.fade-exit-active {
opacity: 0;
transition: opacity 1s ease-in;
}
/* 出画执行完程样式 */
.fade-exit-done {
opacity: 0;
}
8 redux
npm install --save redux
文件目录
- index.js
import { createStore } from 'redux';
import reducer from './reducer.js'
const store = createStore(reducer);
export default store;
- reducer.js
const defaultState = {
inputValue: '111',
list: [1221,232]
}
// state 当前的state 数据, action 是 dispatch 触发过来的一个对象
// reducer 可以拷贝state 不能更改state
export default (state = defaultState, action) => {
// console.log(state, action)
if (action.type === CHANGE_INPUT_VALVUE) {
const newState = JSON.parse(JSON.stringify(state))
newState.inputValue = action.value
return newState
}
if (action.type === ADD_INPUT_VALVUE) {
const newState = JSON.parse(JSON.stringify(state))
newState.list.push(action.value)
newState.inputValue = ''
return newState
}
if (action.type === DELETE_INPUT_VALVUE) {
const newState = JSON.parse(JSON.stringify(state))
newState.list.splice(action.value, 1)
return newState
}
return state
}
- actionType.js
// todolist
export const CHANGE_INPUT_VALVUE = 'CHANGE_INPUT_VALVUE'
export const ADD_INPUT_VALVUE = 'ADD_INPUT_VALVUE'
export const DELETE_INPUT_VALVUE = 'DELETE_INPUT_VALVUE'
- actionCreater.js
import { CHANGE_INPUT_VALVUE, ADD_INPUT_VALVUE, DELETE_INPUT_VALVUE} from './actionType.js'
export const inputChange = (value) => {
return {
type: CHANGE_INPUT_VALVUE,
value: value
}
}
export const inputAdd = (value) => {
return {
type: ADD_INPUT_VALVUE,
value: value
}
}
export const inputDelete = (value) => {
return {
type: DELETE_INPUT_VALVUE,
value: value
}
}
- 获取redux 中的数据
import store from './store'
store.getState() // 获取数据
- 更改数据
import store from './store'
import { inputChange, inputAdd, inputDelete } from './store/actionCreater.js'
// 创建action
const action = inputChange(event.target.value)
// 通过 store.dispatch 方法去修改 redux 中的数据
store.dispatch(action)
- 实现redux 数据更新 自动刷新页面
import store from './store'
import React, { Component } from 'react';
class xxx extends Component {
constructor(props) {
super(props);
this.state = store.getState()
this.handleChange = this.handleChange.bind(this); // 函数中要用 this.setstate, 要更改指针
store.subscribe(this.dataChange) // store.subscribe 订阅 当store中数据发生变化时,就会执行指定的函数
}
render () { return (...) }
dataChange () {
this.setState(store.getState())
}
}
export default xxx
9 react 无状态组件
无状态组件就是只有render 函数的ui组件
- 相比较于 ui 组件 性能高(因为本质上是函数)
// import React, { Component } from 'react';
import React from 'react';
import { List, Input, Button } from 'antd';
// 无状态组件 就是个函数
const TodoListUi = (props) => {
return (
<div>
<div>
<Input placeholder="输入内容"
value={props.inputValue}
onChange={props.handleChange}
style={{width: '300px'}}
/>
<Button onClick={props.addDate} type="primary">提交</Button>
</div>
<List size="small"
bordered
style={{width: '300px'}}
dataSource={props.list}
// 函数传值时, onClick={() => {this.props.handleDelete(index)}} 绑定里一个函数来执行 this.props.handleDelete(index) 函数
renderItem={(item, index) => <List.Item onClick={() => {props.handleDelete(index)}}>{item}</List.Item>}
/>
</div>
)
}
//生成的是react ui组件 包括生命周期函数 construction render 等等
// class TodoListUi extends Component {
// render () {
// return (
// <div>
// <div>
// <Input placeholder="输入内容"
// value={this.props.inputValue}
// onChange={this.props.handleChange}
// style={{width: '300px'}}
// />
// <Button onClick={this.props.addDate} type="primary">提交</Button>
// </div>
// <List size="small"
// bordered
// style={{width: '300px'}}
// dataSource={this.props.list}
// // 函数传值时, onClick={() => {this.props.handleDelete(index)}} 绑定里一个函数来执行 this.props.handleDelete(index) 函数
// renderItem={(item, index) => <List.Item onClick={() => {this.props.handleDelete(index)}}>{item}</List.Item>}
// />
// </div>
// )
// }
// }
export default TodoListUi
10 redux-thunk 处理异步数据
文件目录- store/index.js
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import reducer from './reducer.js'
const store = createStore(reducer, applyMiddleware(thunk));
export default store;
- store/actionCreater.js 添加
...
export const getTodoList = () => {
// 添加 redux-thunk 后, 返回的函数自动就带 dispatch 了
return (dispatch) => {
setTimeout(() => {
dispatch(initTodoList([1,2,3,4,5,6]))
}, 1000);
}
}
...
- store/reducer.js 添加
...
if (action.type === INIT_TODOLIST) {
const newState = JSON.parse(JSON.stringify(state))
newState.list = action.value
return newState
}
...
- store/actionType.js 添加
...
export const INIT_TODOLIST = 'INIT_TODOLIST'
...
- 组件使用
...
componentDidMount () {
store.dispatch(getTodoList())
}
...
https://github.com/reduxjs/redux-thunk
11 搭建react 项目
- 创建 react 项目
npm create-react-app my-app
https://reactjs.bootcss.com/docs/create-a-new-react-app.html
- 插件
npm install styled-components
https://www.npmjs.com/package/styled-components
作为公共样式使用
文件目录style.js
import { createGlobalStyle } from 'styled-components'
export const GlobalStyled = createGlobalStyle`
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
background: green;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
`
app.js
import React, { Component } from 'react';
import { GlobalStyled } from './style.js'
class App extends Component {
render() {
return (
<div className={'fontSize'}>
{/* 样式引入 */}
<GlobalStyled/>
hello world
</div>
)
}
}
export default App
作为组件使用
文件index.js
import React, { Component } from 'react';
import {
HeaderContent,
Logo,
Nav
} from './style';
class Header extends Component {
render () {
return (
<HeaderContent>
<Logo/>
<Nav/>
</HeaderContent>
)
}
}
export default Header;
style.js
import styled from 'styled-components';
import logo from '../../static/logo.png'
export const HeaderContent = styled.div`
position: relative;
height: 58px;
width: 100%;
border-bottom: 1px solid #f0f0f0;
`
export const Logo = styled.div`
position: absolute;
height: 100%;
width: 100px;
float: left;
background: url(${logo});
background-size: contain;
`
export const Nav = styled.div`
height: 100%;
width: 960px;
margin: 0 auto;
background: red;
`
- react react-redux 安装使用
npm install redux react-redux --save-dev
app.js
文件 (入口文件)
...
import {Provider} from 'react-redux'
import store from './store'
class App extends Component {
render() {
return (
<Provider store={store}>
入口文件
</Provider>
)
}
}
export default App
store
文件结构
index.js
import { createStore } from 'redux';
import reducer from './reducers/index.js'
const store = createStore(reducer);
export default store;
actionType.js
export const FOUCESTATE = 'FOUCESTATE'
export const BLURSTATE = 'BLURSTATE'
actionCreater.js
import { FOUCESTATE, BLURSTATE } from './actionType.js'
export const fouceInput = () => {
return {
type: FOUCESTATE
}
}
export const blurInput = () => {
return {
type: BLURSTATE
}
}
reducers/headerReducer.js
import { FOUCESTATE, BLURSTATE } from '../actionType.js'
const defaultState = {
fouce: false
}
// state 当前的state 数据, action 是 dispatch 触发过来的一个对象
// reducer 可以拷贝state 不能更改state
export default (state = defaultState, action) => {
// console.log(state, action)
if (action.type === FOUCESTATE) {
return {
fouce: true
}
}
if (action.type === BLURSTATE) {
return {
fouce: false
}
}
return state
}
reducers/index.js
import { combineReducers } from 'redux'
import headerReducer from './headerReducer.js'
export default combineReducers({
header: headerReducer
})
组件使用
import React, { Component } from 'react';
import {CSSTransition} from 'react-transition-group'
import { connect } from 'react-redux'
import { fouceInput, blurInput } from '../../store/actionCreater.js'
import {
HeaderContent,
Logo,
Nav,
NavItem,
NavInput,
Addtion,
Button,
SearchIcon
} from './style';
class Header extends Component {
render () {
return (
<HeaderContent>
<Logo/>
<Nav>
<NavItem className='left active'>首页</NavItem>
<NavItem className='left'>下载APP</NavItem>
<SearchIcon>
<CSSTransition
in={this.props.fouce}
timeout={200}
classNames="slider"
>
<NavInput placeholder="搜索"
onFocus={this.props.fouceState}
onBlur ={this.props.blurState}
className={this.props.fouce ? 'fouce' : ''}
></NavInput>
</CSSTransition>
<span
className={this.props.fouce ? 'iconfont left active' : 'iconfont left'}
>

</span>
</SearchIcon>
<NavItem className='right gray'>
<span className="iconfont"></span>
</NavItem>
<NavItem className='right gray'>登录</NavItem>
</Nav>
<Addtion>
<Button>注册</Button>
<Button className='active'>
<span className="iconfont"></span>写文章</Button>
</Addtion>
</HeaderContent>
)
}
}
const mapStateToProps = (state) => {
return {
fouce: state.header.fouce
}
}
const mapDispatchToProps = (dispatch) => {
return {
fouceState () {
dispatch(fouceInput())
},
blurState () {
dispatch(blurInput())
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Header);
- immutable 安装
npm install immutable
npm install redux-immutable
store/reducers/headerReducer.js
文件修改
import { FOUCESTATE, BLURSTATE } from '../actionType.js'
import { fromJS } from 'immutable'
const defaultState = fromJS({
fouce: false
})
export default (state = defaultState, action) => {
if (action.type === FOUCESTATE) {
// state.set('fouce', true) 是返回了一个新的对象,并不是修改原来的对象
return state.set('fouce', true)
}
if (action.type === BLURSTATE) {
return state.set('fouce', false)
}
return state
}
store/reducers/index.js
文件修改
import { combineReducers } from 'redux-immutable'
import headerReducer from './headerReducer.js'
export default combineReducers({
header: headerReducer
})
组件使用
...
const mapStateToProps = (state) => {
return {
fouce: state.get('header').get('fouce')
}
}
...
export default connect(mapStateToProps, mapDispatchToProps)(Header);
https://github.com/immutable-js/immutable-js
- 添加路由
npm install react-router-dom --save-dev
app.js
...
import { BrowserRouter, Route } from 'react-router-dom'
import Detail from './pages/detail'
import Home from './pages/home'
...
class App extends Component {
render() {
return (
<Provider store={store}>
<div className={'fontSize'}>
....
<Header/>
<BrowserRouter>
<div>
<Route path='/' exact component={Home}></Route>
<Route path='/detail' exact component={Detail}></Route>
//带参数路由
<Route path='/detail/:id' exact component={Detail}></Route>
</div>
</BrowserRouter>
</div>
</Provider>
)
}
}
export default App
link 使用
import { Link } from 'react-router-dom';
class Lists extends PureComponent {
render () {
return (
<Link key={item.get('id')} to='/detail'>
<Link key={item.get('id')} to={'/detail/'+ item.get('id')}>
....
</Link>
)
}
}
获取路由参数
this.props.match.params // 动态路由获取参数
- react 事件监听
class Home extends Component {
...
componentDidMount () { // 监听事件
this.bindEvents()
}
componentWillUnmount () { // 记得移除
window.removeEventListener('scroll', this.props.changeFlag)
}
bindEvents () {
window.addEventListener('scroll', this.changeFlag)
}
changeFlag (e) {
console.log(e)
}
...
}
- react 组件
PureComponent
网友评论