1. 搭建环境

npm install -g creat-react-app
# 创建一个项目
create-react-app jianshu
cd jianshu
npm run start
# 安装styled-components 全局统一管理css
npm install --save styled-components
# 全局样式引入
https://meyerweb.com/eric/tools/css/reset/
background-size: contain;

2. React知识点

1. 组件

组件:就是将整个UI拆分为很多小的,可重用的UI,每一个小的UI独立做自己的事情。

1.1 定义一个组件

一个组件需要继承React.Component 重写render()函数,返回JSX

注意点:

1.只要有JSX的地方必须引入React

2.返回值中只能有一个元素包裹,div包裹整个JSX,如下是错误的返回方式

return (
<div>
hello world
</div>
<div>
hello world
</div>
);
import React, { Component } from 'react';
class App extends Component {
render() {
return (
<div>
hello world
</div>
);
}
}
export default App;

1.2 组合与拆分组件

引用官方的一句话:Don’t be afraid to split components into smaller components.

尽可能的让每一个组件都能分工明确,减少重复,加大可重用。例如表格组件,就必须被拆分为一个单独的组件,它可能在各个地方被用到。

组件拆分优点:让开发显得更加清晰明了。

未拆分组件看起来就没有食欲

return (
<div className="Comment">
<div className="UserInfo">
<img className="Avatar"
src={props.author.avatarUrl}
alt={props.author.name}
/>
<div className="UserInfo-name">
{props.author.name}
</div>
</div>
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
);

1.案例解析

将首页拆分为Header, Right,如下定义一个首页组件,在首页组件中分别引入Header和Right组件,这就是一个简单的组件拆分和组合.

<React.Fragment />是一个虚拟的组件,仅仅是为了包裹其中的元素,并不会出现在页面上

Index.js

import React from 'react'
import Header from './Header'
import Right from './Right'
class Index extends React.Component {
render() {
return (
<React.Fragment>
<Header />
<Right />
</React.Fragment>
);
}
}
export default Index

Header.js

import React from 'react'
class Header extends React.Component {
render() {
return (
<React.Fragment>
<div>i am header component</div>
</React.Fragment>
);
}
}
export default Header

Right.js

import React from 'react'
class Right extends React.Component {
render() {
return (
<React.Fragment>
<div>i am right component</div>
</React.Fragment>
);
}
}
export default Right

1.3 组件传值

组件传值分为以下几种情况:1. 父组件传值到子组件;2.子组件向父组件传值;3.隔代组件传值

1. 父传子

注意点: props是只读的

例如Index.jsHeader.js组件传值

	{/* Index.js 传递title属性 */}
return (
<React.Fragment>
<Header title="Header Title"/>
<Right />
</React.Fragment>
); {/*Header.js 接受值*/}
return (
<React.Fragment>
<div>{this.props.title}</div>
</React.Fragment>
);

1.4 state

state可以用来存储数据,记性状态管理。

it is private and fully controlled by the component.

render函数执行:组件state和props发生改变,render函数会被执行,当父组件重新渲染时候,子组件render函数也会被重新执行

class Index extends React.Component {

  constructor(props) {
super(props)
this.state = {
title: 'Header title'
}
} render() {
return (
<React.Fragment>
<Header title={this.state.title}/>
<Right />
</React.Fragment>
);
}
}
export default Index

1.5 PropTypes

https://reactjs.org/docs/typechecking-with-proptypes.html

当组件之间传值的时候,接收一方往往需要对参数进行校验,这就是PropTypes的作用

import PropTypes from 'prop-types'

class ReactUI extends React.Component {
render() {
return ( )
}
}
//属性类型
ReactUI.propTypes = {
//表示name必须是string类型
name: PropTypes.string
//属性必传
id: PropTypes.element.isRequired
}

默认值

The propTypes typechecking happens after defaultProps are resolved

class Greeting extends React.Component {
static defaultProps = {
name: 'stranger'
} render() {
return (
<div>Hello, {this.props.name}</div>
)
}
}

1.5 生命周期函数

在页面加载的过程中,特定时间点自动执行的函数称为生命周期函数。

生命周期的四个阶段:

  1. Initialization

这一阶段主要加载props和state

  1. Mounting:页面第一次加载的时候才会执行的挂载

componentWillMount:在组件即将被挂载到页面的时刻执行

render:

componentDisMount:在组件挂载完成之后会被执行

​ 使用场景:用于发送ajax请求

  1. Updation:数据发生变化的时候会被执行
  • props:

componentWillReceiveProps:

​ 子组件从父组件接受属性,第一次存在父组件,render函数执行,该函数不会被执行,当父组件render函数重新被执行,就会执行这个函数

shouldComponentUpdate:组件是否需要被更新,返回boolean值

​ 使用场景:shouldComponentUpdate(nextProps, nextState);这两个参数来接受即将改变的props和state的值;演示:

  shouldComponentUpdate(nextProps, nextState) {
if (nextProps.title !== this.props.title) { //放生改变,则需要重新渲染
return true
} else {
return false
}
}

componentWillUpdate: 当组件被更新之前被执行,但是取决于shouldComponentUpdate的返回结果,

render

componentDidUpdate:组件更新完成之后会被执行

  • states:

shouldComponentUpdate

componentWillUpdate

componentDidUpdate:

  1. Unmounting

componentWillUnmount: 组件从页面移除的时候会被执行

1.6 无状态组件

无状态组件: 就是组件中只含有render()函数的组件,

import React from 'react'

class Header extends React.Component {
render() {
return (
<React.Fragment>
<div>xx {this.props.title}</div>
</React.Fragment>
);
}
}
export default Header

这种组件可以被简化为无状态组件

export default (props, context) => {
return (
<React.Fragment>
<div>xx {props.title}</div>
</React.Fragment>
);
}

1.7 List and Key

案例:使用List集合渲染一个页面

key的作用:

Keys help React identify which items have changed, are added, or are removed. Keys should be given to the elements inside the array to give the elements a stable identity

这个主要和虚拟DOM有关,可以提高虚拟DOM性能。

兄弟姐妹之间的key必须独一无二

import React from 'react'

class Event extends React.Component {

  constructor(props) {
super(props)
this.state = {
data: [1, 2, 3, 4, 5, 6, 7]
} this.handClick = this.handClick.bind(this);
}
render() {
return (
<div>
<ul>
{
this.state.data.map((item) => (
<li key={item}>{item}</li>
))
}
</ul>
</div>
)
}
}
export default Event

2. JSX

JSX 既不是string也不是html,是React独有的一种语法,jsx中需要注意的点:

  1. 标签的类class 如:<div class='show'></div> 会和ES6关键字冲突会使用className代替
  2. <label></label> for属性也会使用htmlFor 代替

3. 虚拟DOM

虚拟DOM就是一个JS对象,用来描述真实DOM

jsx转换成js对象

<div className='show'>hello world</div>
React.createElement('div',{className: 'show'}, 'hello world');

流程讲解

  1. state数据
  2. jsx模板
  3. 数据 + 模板生成虚拟DOM
  4. 使用虚拟DOM来来生成真实DOM, 显示在页面上
  5. state发生改变
  6. 数据 + 模板生成新的虚拟DOM
  7. 比较原始的虚拟DOM和新的虚拟DOM之间的区别,找到不同之处
  8. 操作DOM,改变不同的地方

diff算法

上面的第七步骤是如何比对不同之处呢,这里使用了diff算法。

同层比对:第一层有差异,则不会再进行比对,直接向下全部渲染,如果第一层相同,则向下继续比较。

根据Key做关联来进行比对: 同层的key必须固定不变,这样才能再进行比对的时候准确的找到原始的dom节点。假如使用index作为key值,当删除一个元素,那个被删除元素后面的所有标签key值都会被改变,那么进行比对的时候,就会出现性能消耗。

5. 函数绑定

React events are named using camelCase, rather than lowercase.

例如onClick, onBlur...

import React from 'react'
import './event.css' class Event extends React.Component { constructor(props) {
super(props)
this.state = {
isShow: true
}
}
render() {
return (
<div>
<button onClick={this.handClick.bind(this)}>切换</button>
<div className={this.state.isShow ? 'show':'hidden'}>你好</div>
</div>
)
} handClick() {
this.setState((state) => ({
isShow: !state.isShow
}))
}
}
export default Event

传递参数

render() {
return (
<div>
<button onClick={() => this.handClick(this.state.isShow)}>切换</button>
<div className={this.state.isShow ? 'show':'hidden'}>你好</div>
</div>
)
} handClick(isShow) {
this.setState((state) => ({
isShow: !isShow
}))
}

传递参数的几种方式

<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
<SearchSwitch onClick={() => switchItem(page, totalPage)}>换一批</SearchSwitch>

3. Redux

https://redux.js.org/introduction/getting-started

# 安装
npm install --save redux

1. 了解是三个概念

Actions: 就像一个快递,里面包含地址(行为),以及物品(数据)

Reducers:就像一个快递员,负责分发不同的快递,根据地址(行为)派送到不同地方

Store: 就像一个总站,可以存储这些快递,最后返回给用户。

与物流之间的区别就是:store不可变,只可以返回数据,而原先的数据一直保留在store里面

1.1 演示

第一步:创建Store index.js

这里借助redux createStore方法创建store,并且引入reducer

import { createStore } from 'redux'
import reducer from './Reducers' const store = createStore(
reducer,
// 这个可以使用Chrome redux 插件进行调试
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
)
export default store

第二步:创建一个reducer

reducer 里面保存数据的初始状态,defaultState

解析action的行为

const defaultState = {
list: ['hello', 'world']
} const reducer = (state = defaultState, action) => {
switch (action.type) {
case 'add_list_action':
return {list: action.data}
default:
return state
}
}
export default reducer

第三步:使用redux

  1. this.state = store.getState() 从store中获取数据
  2. store.subscribe(this.handSubscribe)订阅数据,监听数据的变化
  3. handClick()方法中主要定义action,然后利用store进行分发
import React from 'react'
import store from './store' class ReduxUI extends React.Component { constructor(props) {
super(props)
this.state = store.getState()
this.handClick = this.handClick.bind(this)
this.handSubscribe = this.handSubscribe.bind(this)
store.subscribe(this.handSubscribe)
} render() {
return (
<div>
<button onClick={this.handClick}>点击我</button>
<ul>
{
this.state.list.map((item) => {
return <li key={item}>{item}</li>
})
}
</ul>
</div>
)
}
handClick() {
//创建一个Action
const addListAction = () => ({
type: 'add_list_action',
data: ['1', '2', '3']
})
//这是一个异步操作
store.dispatch(addListAction())
} handSubscribe() {
this.setState(store.getState())
}
}
export default ReduxUI

2. react-redux中间件

改造1>1.1 中的代码

nmp install --save react-redux

新增加一个父组件,统一管理store,

这个组件拥有store,<Provider store={store}>表示改下面的所有元素都可以使用store中的数据

import React, { Component } from 'react';
import store from './pages/redux/store'
import { Provider } from 'react-redux'
import ReduxUI from './pages/redux/ReduxUI'
class App extends Component {
render() {
return (
<Provider store={store}>
<ReduxUI/>
</Provider>
);
}
} export default App;

步骤三中的修改

第一步:添加connect 方法

第三步:映射state中的属性,定义分发的方法

第四步:连接组件

import React from 'react'
import {connect } from 'react-redux' class ReduxUI extends React.Component { render() {
//从react-redux中接收store中的信息,以及分发action的方法
const { list, handClick } = this.props
return (
<div>
<div>
<button onClick={handClick}>点击我</button>
<ul>
{
list.map((item) => {
return <li key={item}>{item}</li>
})
}
</ul>
</div>
</div>
)
} }
//state就是store中state
const mapStateToProps = (state) => ({
list: state.list
})
//这里定义分发action的方法,dispatch 就是store的dispatch方法
const mapDispatchProps = (dispatch) => ({
handClick() {
//创建一个Action
const addListAction = () => ({
type: 'add_list_action',
data: ['1', '2', '3']
})
dispatch(addListAction())
}
})
//连接组件,并且把属性和action行为传递给组件
export default connect(mapStateToProps, mapDispatchProps)(ReduxUI)

4. 其他

1. Redux-thunk

Redux Thunk middleware allows you to write action creators that return a function instead of an action

npm install redux-thunk

to enable Redux Thunk, useapplyMiddleware()

这里配合redux-devtools-extension调试工具一起使用

import { createStore, compose, applyMiddleware } from 'redux'
import reducer from './reducer'
import thunk from 'redux-thunk'
// 这个就是让调试插件配合中间件使用
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose const store = createStore(
reducer,
composeEnhancers(applyMiddleware(thunk))
)
export default store
// 定义一个方法,处理鼠标聚焦行为
//然后dispatch分发action
handFocus(list) {
(list.size === 0) && dispatch(actionCreator.getSearchItems())
dispatch(actionCreator.inputFocusAction())
} //另外一个文件
//===================================
// 这里就是上面的action,这个action是一个方法,在该方法里面发送ajax异步请求,
//异步请求之后继续分发另外一个action
export const getSearchItems = () => {
return (dispatch) => {
axios.get("/api/item.json").then((res) => {
dispatch(searchItemsAction(res.data.data))
})
}
}

正如官方文档所说:redux-thunk允许你分发一个方法类型的action

2. Redux-saga

asynchronous things like data fetching and impure things like accessing the browser cache

npm install --save redux-saga
import { createStore, compose, applyMiddleware } from 'redux'
import reducer from './Reducers'
import createSagaMiddleware from 'redux-saga'
import reduxSaga from './reduxSaga'
const sagaMiddleware = createSagaMiddleware()
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
const store = createStore(
reducer,
composeEnhancers(applyMiddleware(sagaMiddleware))
)
//运行自己的reduxSaga
sagaMiddleware.run(reduxSaga) export default store

reduxSaga.js

import { takeEvery, put } from 'redux-saga/effects'
import axios from 'axios' function* getJson() {
const res = yield axios.get('./data.json')
yield put({type:"add_list_action", data: res.data}) //继续派发action
} function* reduxSaga() {
// 当store分发'add_list_action' 这个action的时候,会调用getJson方法
yield takeEvery("add_list__pre_action", getJson)
}
export default reduxSaga

5. immutable

immutable可以保证数据一旦创建,就不会被改变

npm install --save immutable
//目的:将store变成不可变,这是一个简单reducer.js
import * as constants from './constant' //es6语法
import { fromJS } from 'immutable'
//这里将defaultStore变成一个immutable对象
const defaultStore = fromJS({
focused: false,
mouseIn: false,
list: [],
page: 1,
totalPage: 1
}) export default (state = defaultStore, action) => {
switch (action.type) {
case constants.input_focused:
//这里的set immutable对象的一个值,其实并不是改变了state,而是返回一个新的对象
//通过set可以简化我们的操作,不用重新构建全部的对象
return state.set('focused', true)
default:
return state
}
} // 如何获取一个immutable对象呢?
const mapStateToProps = (state) => ({
//这里表示获取header组件下的一个immutable对象
//这里是 redux-immutable 获取数据的形式
// state.header.get('focused') 为immutable获取数据的格式
focused: state.getIn(['header', 'focused']), //state.get('header').get('focused')
mouseIn: state.getIn(['header', 'mouseIn']),
list: state.getIn(['header', 'list']),
page: state.getIn(['header', 'page']),
totalPage: state.getIn(['header', 'totalPage'])
}) //通过action传递参数的时候也应该是一个immutable对象
export const searchItemsAction = (data) => ({
type: constants.render_list,
data: fromJS(data),
totalPage: Math.ceil(data.length / 10)
})

5.1 redux-immutable

redux-immutable is used to create an equivalent function of Redux combineReducers that works with Immutable.jsstate.

我们经常面临很多很多组件,但是如果把所有组件的store,reducer, action 维护在一个目录下,那将是惨目忍睹的,所以通常情况下我们会分开管理redux,然后将所有的reducer组合在一起

npm install --save redux-immutable
//import { combineReducers } from 'redux'
import { combineReducers } from 'redux-immutable' //可以管理immutale对象
import { reducer as headerReducer} from '../header/store' const reducer = combineReducers({
header: headerReducer
})
export default reducer

5. react-router-dom

React Router is a collection of navigational components that compose declaratively with your application.

npm install --save react-router-dom
import { BrowserRouter, Route } from "react-router-dom"
...
<BrowserRouter>
{/* 表示路由到一个组件 */}
<Route path="/home" exact component={Home} />
</BrowserRouter>

Route: 表示要路由的到哪一个组件

Link: 表示一个连接,跳转到某个页面

6. react-loadable

一个项目,不同的页面应该按需加载,而不是当首页出来之后加载所有的组件,例如我们访问首页的时候只会加载首页相关的资源,访问详情页的时候加载详情页的代码,这样可以提高首页访问速度以及用户体验

npm install --save react-loadable

案例演示

import React from 'react'
import Loadable from 'react-loadable'
const LoadableComponent = Loadable({
//这里`reactUI`是一个组件,表示这个组件将会被按需加载
loader: () => import('./reactUI'),
// 这里是一个函数,可以是一个组件,表示页面加载前的状态
loading: () => <div>正在加载</div>
})
//返回无状态组件
export default () => {
return <LoadableComponent/>
}

7. 在React 使用各种CSS

1. styled-components

npm install --save styled-components

定义全局样式

import { createGlobalStyle } from 'styled-components'
export const ResetCSS = createGlobalStyle`
body {
line-height: 1;
}
....
`
// 引用全局样式
import { ResetCSS } from './style'
...
render() {
return (
<ResetCSS />
)
}

React实战一的更多相关文章

  1. 【转】Delphi+Halcon实战一:两行代码识别QR二维码

    Delphi+Halcon实战一:两行代码识别QR二维码 感谢网友:绝代双椒( QQ号应原作者要求隐藏了:xxxx6348)的支持 本文是绝代双椒的作品,因为最近在忙zw量化培训,和ziwang.co ...

  2. C蛮的全栈之路-node篇(二) 实战一:自动发博客

    目录 C蛮的全栈之路-序章 技术栈选择与全栈工程师C蛮的全栈之路-node篇(一) 环境布置C蛮的全栈之路-node篇(二) 实战一:自动发博客 ---------------- 我是分割线 ---- ...

  3. 【实战】Docker 入门实战一:ubuntu 和 centos 安装Docker

    Docker是什么 Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从Apache2.0协议开源.Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级.可移植的容器中,然后发布 ...

  4. 机器学习实战一:kNN手写识别系统

    实战一:kNN手写识别系统 本文将一步步地构造使用K-近邻分类器的手写识别系统.由于能力有限,这里构造的系统只能识别0-9.需要识别的数字已经使用图形处理软件,处理成具有相同的色彩和大小:32像素*3 ...

  5. zookeeper curator ( 实战一)

    目录 zookeeper 的伪集群搭建 写在前面 1.1. zookeeper 安装&配置 1.1.1. 创建数据目录和日志目录: 1.1.2. 创建myid文件 1.1.3. 创建和修改配置 ...

  6. Netty聊天器(实战一):从0开始实战100w级流量应用

    Java 聊天程序(百万级流量实战一):系统介绍 疯狂创客圈 Java 分布式聊天室[ 亿级流量]实战系列之14 [博客园 总入口 ] 源码IDEA工程获取链接:Java 聊天室 实战 源码 写在前面 ...

  7. 【k8s实战一】Jenkins 部署应用到 Kubernetes

    [k8s实战一]Jenkins 部署应用到 Kubernetes 01 本文主旨 目标是演示整个Jenkins从源码构建镜像到部署镜像到Kubernetes集群过程. 为了简化流程与容易重现文中效果, ...

  8. miniFTP项目实战一

    项目简介: 在Linux环境下用C语言开发的Vsftpd的简化版本,拥有部分Vsftpd功能和相同的FTP协议,系统的主要架构采用多进程模型,每当有一个新的客户连接到达,主进程就会派生出一个ftp服务 ...

  9. React Native实战一

    效果图如下所示: 展示列表页面,点击跳转至详情页面:     /** * Sample React Native App * https://github.com/facebook/react-nat ...

随机推荐

  1. Hive是读时模式

    Hive处理的数据是大数据,在保存表数据时不对数据进行校验,而是在读数据时校验,不符合格式的数据设置为NULL: 读时模式的优点是,加载数据库快. 传统的数据库如mysql.oracle是写时模式,不 ...

  2. SQL Server ->> 使用CROSS APPLY语句是遇到聚合函数中包含外部引用列时报错

    本次遇到的问题是CROSS APPLY的内部查询语句中的聚合函数包含CASE WHEN判断,且同时又内部语句的表的列和外部引用的表的列,此时会报下列的错误. 消息 8124,级别 16,状态 1,第 ...

  3. 一些简单的SQL Server服务器监控

    1:磁盘活动的一些监控 指标 吞吐量:IOPS,存储子系统每秒能提供多少次I/O 吞吐量,MB/S,I/O子系统每秒能提供多少MB 延时:每个I/O请求占用多少时间 队列长度:队列中有多少IO请求在等 ...

  4. 转: c#.net利用RNGCryptoServiceProvider产生任意范围强随机数的办法

    //这样产生0 ~ 100的强随机数(含100) ; int rnd = int.MinValue; decimal _base = (decimal)long.MaxValue; ]; System ...

  5. [翻译] DoImagePickerController

    DoImagePickerController An image picker controller with single selection and multiple selection. Sup ...

  6. 用windows自带的fsutil修改稀疏文件大小成功,但文件内容似乎丢失

    fsutil sparse setflag. fsutil sparse setrange 10M对应字节,1G对应字节.. 看文件属性,实际尺寸是小了,但内容似乎也丢了..因为自己把该文件做成虚拟盘 ...

  7. 笔记本无密码连接wifi

    用手机可以用wifi万能钥匙破解wifi,就想找电脑版的wifi万能钥匙,然并卵. 就去寻找各种办法,最后找了个巧, 用手机下载wifi万能钥匙连接,并且使用数据线连接上笔记本. 然后手机设置中找到开 ...

  8. Eclipse validation

    window->preferences->validation 可以取消部分文件的验证,取消build时验证,改为手动验证,提高效率.

  9. 转载】JQuery中如何传递参数如click(),change()等具体实现

    转载地址:http://www.jb51.net/article/36249.htm 有个需求让两个select中option相互转换,这个作业就是给几个按钮添加click()事件接下来为大家介绍下如 ...

  10. Java虚拟机15:运行期优化

    前言 HotSpot采用的是解释器+编译器并存的架构,之前的这篇文章里面已经讲过了,本文只是把即时编译器这块再讲得具体一点而已.当然,其实本文的内容也没多大意义,90%都是概念上的东西,对于实际开发. ...