React

React

react生命周期函数

参考文档:https://segmentfault.com/a/1190000015025236

在这里插入图片描述

创建react项目

npx create-react-app 项目名(不能有大写字母)

父子组件之间传值

参考文档:https://www.cnblogs.com/chujunqiao/p/11795422.html

React 中ref的几种用法

1.字符串

通过 this.refs.a 来引用真实dom的节点
dom 节点上使用

 <input  type ="text" ref="a"/> 
2.回调函数

回调函数就是在dom节点或组件上挂载函数,函数的入参是dom节点或组件实例,达到的效果与字符串形式是一样的,
都是获取其引用。

<input type="text" ref={(input)=>{this.textInput=input}} 
3.React.createRef()

在React 16.3版本后,使用此方法来创建ref。将其赋值给一个变量,通过ref挂载在dom节点或组件上,该ref的current属性将能拿到dom节点或组件的实例

class Counter extends Component {
    constructor() {
        super()
        this.state ={sum:0,number:0}
        this.myRef = React.createRef();
    }
    change = () =>{
        this.setState({...this.state,sum: Number(this.textInput.value) + Number(this.myRef.current.value)})
    }
    componentDidMount(){
        console.log(this.myRef.current.value);
    }
    render() {
        return (
            <div onChange ={this.change} >
                <input type="text" ref={(input)=>{this.textInput=input}} />+ 
                <input  type ="text" ref={this.myRef} /> = {this.state.sum}
            </div>
            
        )
    }
}

案例:

通过ref获取form实例对象,也可以是值或者方法

子组件

import React, { Component } from 'react'
import { Form, Input, Button, Checkbox } from 'antd';

export default class Children extends Component {
    render() {
        const layout = {
            labelCol: { span: 8 },
            wrapperCol: { span: 16 },
        };
        const tailLayout = {
            wrapperCol: { offset: 8, span: 16 },
        };
        const onFinish = values => {
            console.log('Success:', values);
        };

        const onFinishFailed = errorInfo => {
            console.log('Failed:', errorInfo);
        };


        return (
            <Form ref={e => { this.addForm = e }}
                {...layout}
                name="basic"
                initialValues={{ remember: true }}
                onFinish={onFinish}
                onFinishFailed={onFinishFailed}
            >
                <Form.Item
                    label="Username"
                    name="username"
                    rules={[{ required: true, message: 'Please input your username!' }]}
                >
                    <Input />
                </Form.Item>

                <Form.Item
                    label="Password"
                    name="password"
                    rules={[{ required: true, message: 'Please input your password!' }]}
                >
                    <Input.Password />
                </Form.Item>

                <Form.Item {...tailLayout} name="remember" valuePropName="checked">
                    <Checkbox>Remember me</Checkbox>
                </Form.Item>

                <Form.Item {...tailLayout}>
                    <Button type="primary" htmlType="submit">
                        Submit
        </Button>
                </Form.Item>
            </Form>
        )
    }
}

父组件

import React, { Component } from 'react'
import { Button } from 'antd'
import Children from './children'

export default class Parent extends Component {
    /**
     * 需要在子组件中form表单中加入ref={e=>{this.addForm = e}}来获取form对象
     */
    getComponent = () => {
        console.log(this.textInput.addForm)
    }
    render() {
        return (
            <div>
                <Button type="success" onClick={() => { this.getComponent() }}>获取子组件的form对象</Button>
                <Children ref={e => { this.textInput = e }} />
            </div>
        )
    }
}

Props

用于组件之间数据的传递

export default class Home extends React.Component {
    //渲染函数
    render() {
        const nav1 = ['web','app']
        const nav2 = ['java','react']
        return (
            <div>
                <App nav={ nav1 } title="文章列表"/>
                <App nav={ nav2 } title="文章详情"/>
            </div>)
    }
}

通过props获取nav和title

export default class App extends React.Component {
    render() {
        return (
            <div> 
                {/* 获取title*/}
                <h1>{this.props.title}</h1>
                {/*jsx语法,props 获取nav*/}
                <ul>
                    {
                        this.props.nav.map((element,index)=>{
                            return <li key={index}>{element}</li>
                        })
                    }
                </ul>
            </div>
        )
    }
}

state

修改元素的变化使用state

export default class StateComponent extends React.Component{
     // 初始化state
    constructor(){
        super()
        this.state = {
            count:1,
            flag: true
        }
    }
    
  increment(){
        //通过setState方法来修改state中count的值
        this.setState({
           count: this.state.count+1
        }) 
    }
    
    render(){
        let showView = this.state.flag ? '已登录' : '未登录'
        return (
            <div>
                {this.state.count}
                <br/>
                <button onClick={this.increment.bind(this)}>增加</button>
                <h1>{showView}</h1>
            </div>
        )
    }
}

setState同步异步问题

参考文档:https://blog.csdn.net/sinat_17775997/article/details/77100815

Fetch的使用

处理get和post请求

官网:https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch

案例:https://blog.csdn.net/qq_34475058/article/details/84238108

react跨域问题

参考文档:https://www.jianshu.com/p/4a7f26adbedf

setupProxy.js

const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app){
    app.use('/api', createProxyMiddleware(
        { 
            target: 'http://47.96.0.211:9000', 
            changeOrigin: true,
        }
    ))
}

react 路由

英文文档:https://reactrouter.com/web/guides/quick-start

中文文档:https://www.jianshu.com/p/97e4af32811a

安装:npm install react-router-dom

案例:使用了link和

两种方式

import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";

export default function App() {
return (
 <Router>
   <div>
     <nav>
       <ul>
         <li>
           <Link to="/">Home</Link>
         </li>
         <li>
           <Link to="/about">About</Link>
         </li>
         <li>
           <Link to="/users">Users</Link>
         </li>
       </ul>
     </nav>

     {/* A <Switch> looks through its children <Route>s and
         renders the first one that matches the current URL. */}
     <Switch>
       <Route path="/about">
         <About />
       </Route>
       <Route path="/users">
         <Users />
       </Route>
       <Route path="/">
         <Home />
       </Route>
     </Switch>
   </div>
 </Router>
);
}

function Home() {
return <h2>Home</h2>;
}

function About() {
return <h2>About</h2>;
}

function Users() {
return <h2>Users</h2>;
}

Antd

为了提高性能:因为在加载antd组件时会将css、js全部加载进来,性能会降低所以要使用按需加载

使用第一种方法 babel-plugin-import(需要注意不能先上传git中,先把项目中的隐藏文件.git文件夹删除)

按需加载:https://blog.csdn.net/qq_40273756/article/details/103409009和https://segmentfault.com/a/1190000019781597【这个方式还需要修改package.json的script如下】

"scripts":{
 "start":"react-app-rewired start",
  "build":"react-app-rewired build",
  "test":"react-app-rewired test",
  "eject":"react-scripts eject"
}

**自定义主题和react集成less文件[类似css文件,可以使用嵌套样式]文档:**https://blog.csdn.net/weixin_44606225/article/details/107499892

Redux

官网:http://cn.redux.js.org/

参考资料:http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_one_basic_usages.html

redux和react-redux:https://blog.csdn.net/qq_42767631/article/details/83096841和https://segmentfault.com/a/1190000015396885

redux获取store中的数据:https://www.cnblogs.com/luguankun/p/11229020.html

**定义:**Redux是 JavaScript 状态容器,提供可预测化的state状态管理

在这里插入图片描述

Redux三大原则

1、唯一数据源

整个应用的state都被存储到一个状态树里面,并且这个状态树,只存在于唯一的store中

2、保持只读状态

state是只读的,唯一改变state的方法就是触发action,action是一个用于描述以发生时间的普通对象

3、数据改变只能通过纯函数执行

使用纯函数来执行修改,为了描述action如何改变state的,你需要编写reducers

store、state和action之间的关系

stroe 保存数据
action领导 下达命令
reducer员工 执行命令

(一)store

store就是保存数据的地方,你可以把它看成一个数据,整个应用智能有一个store

Redux提供createStore这个函数,用来生成Store

提供方法: getState(), dispatch(action), subscribe(listener)

import {createStore} from 'redux'
const store=createStore(fn);

(二) State

state就是store里面存储的数据,store里面可以拥有多个state,Redux规定一个state对应一个View,只要state相同,view就是一样的,反过来也是一样的,可以通过**store.getState( )**获取

import {createStore} from 'redux'
const store=createStore(fn);
const state=store.getState()

(三)Action

state的改变会导致View的变化,但是在redux中不能直接操作state也就是说不能使用this.setState来操作,用户只能接触到View。在Redux中提供了一个对象来告诉Store需要改变state。Action是一个对象其中type属性是必须的,表示Action的名称,携带的数据是字符串‘redux原理’,Action描述当前发生的事情,这是改变state的唯一的方式

默认是对象(同步action), {type: ‘xxx’, data: value}, 需要通过对应的actionCreator产生,
它的值也可以是函数(异步action), 需要引入redux-thunk才可以

const action={
  type:'ADD_TODO',
  payload:'redux原理'
}

(四)dispatch( )

dispatch(action )是view发出Action的唯一办法,接收一个Action作为参数,将它发送给store通知store来改变state,触发reducer调用

import { createStore } from 'redux';
const store = createStore(fn);

dispatch({
  type: 'ADD_TODO',
  payload: 'Learn Redux'
});

(五) Reducer

Store收到Action以后,必须给出一个新的state,这样view才会发生变化。这种state的计算过程就叫做Reducer。根据老的state和指定的action, 返回一个新的state
不能修改老的state

const reducer =(state,action)=>{
  switch(action.type){
    case ADD_TODO:
        return newstate;
    default return state
  }
}

(六)bindActionCreators

作用:bindActionCreators的作用是将一个或多个action和dispatch组合起来生成mapDispatchToProps需要生成的内容。

参考文档:https://www.cnblogs.com/mengff/p/9530286.html

(七)combineReducers

作用:把一个由多个不同 reducer 函数作为 value 的 object,合并成一个最终的 reducer 函数,然后就可以对这个 reducer 调用 createStore。

参考文档:https://www.jianshu.com/p/6a041ad8abdb

(八)中间件redux-thunk

作用:处理异步的中间件

参考文档:https://www.jianshu.com/p/51c8eaa9fa2a

**案例:**使用redux

app.jsx

import React from 'react';
import { Button } from 'antd';

export default class App extends React.Component {

  render() {
    return (
      <>
        <h1>{this.props.value}</h1>
        <Button onClick={this.props.onIncrement} type="primary" block >
          increment
      </Button>
        <Button onClick={this.props.onDecrement} block>
          decrement
        </Button>
      </>
    )
  }
}

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App'
import { createStore } from 'redux'
import reducer from './reducers/counter'

//redux创建一个仓库
const store = createStore(reducer)
//添加一个render方法,使页面重新渲染,否则页面上的值不会改变
const render = ()=>{
  ReactDOM.render(
    <App 
      onIncrement = {()=>{store.dispatch({type:"INCREMENT"})}}
      onDecrement = {()=>{store.dispatch({type:"DECREMENT"})}}
      value = {store.getState()}
    />,
    document.getElementById('root')
  );
}
render()
store.subscribe(render)

reducer中的counter.js

const counter = (state = 0,action) =>{
    switch(action.type){
        case "INCREMENT":
            return state+1;
        case "DECREMENT":
            return state-1;
        default:
             return state;
    }
}
export default counter

React-redux

需要引用redux,react-redux,redux-thunk,redux-devtools-extension(在chrome浏览器中使用redux工具)

定义:React-Redux是Redux的官方React绑定库。它能够使你的React组件从Redux store中读取数据,并且向store分发actions以更新数据

案例:react-redux流程:https://blog.csdn.net/m0_37282983/article/details/77982564

Provider

connect方法生成容器组件以后,需要让容器组件拿到state对象,才能生成 UI 组件的参数。一种解决方法是将state对象作为参数,传入容器组件。但是,这样做比较麻烦,尤其是容器组件可能在很深的层级,一级级将state传下去就很麻烦。React-Redux 提供Provider组件,可以让容器组件拿到state

下面代码:在最外层容器中,把所有内容包裹在 Provider 组件中,将之前创建的 store 作为 prop 传给 Provider ,App的所有子组件就默认都可以拿到state

import { Provider } from 'react-redux'
import { createStore } from 'redux'
import todoApp from './reducers'
import App from './components/App'

let store = createStore(todoApp);

render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)

connect

作用是将UI 组件生成容器组件

UI组件:如

const Title =
value => <h1>{value}</h1>;
  • 只负责 UI 的呈现,不带有任何业务逻辑
  • 没有状态(即不使用this.state这个变量)
  • 所有数据都由参数(this.props)提供
  • 不使用任何 Redux 的 API

容器组件:

  • 负责管理数据和业务逻辑,不负责 UI 的呈现
  • 带有内部状态
  • 使用 Redux 的 API
import { connect } from 'react-redux'

const VisibleTodoList = connect(
  mapStateToProps, //是否需要一般属性,如果是就写这个,否则不需要
  mapDispatchToProps //是否需要函数属性,如果是就写这个,否则不需要
)(TodoList)
//统一格式:
	connect(
    	state=>({key:value}),
        {action中的方法} //如不需要放一个{}即可
    )(ui组件)
//例子:
 connect(
  state => ({user:state.user}),
  {setHeadTitle}
)(withRouter(LeftNav))
mapStateToProps()

参考文档:https://www.cnblogs.com/orzzt/p/9831343.html

负责输入逻辑,即将state映射到 UI 组件的参数(props),mapStateToProps执行后应该返回一个对象,Redux中的数据映射到React中的props中去

getVisibleTodos也是一个函数,可以从state算出 todos 的值

const mapStateToProps = (state) => {
  return {
    todos: getVisibleTodos(state.todos, state.visibilityFilter)
  }
}
mapDispatchToProps()

负责输出逻辑,将用户对 UI 组件的操作映射成 Action。它定义了哪些用户的操作应该当作 Action,传给 Store,使用时this.props.onClick即可

const mapDispatchToProps = (dispatch,ownProps) => { 
  return {
    onClick: () => {
      dispatch({
        type: 'SET_VISIBILITY_FILTER',
        filter: ownProps.filter
      });
    }
  };
}

案例:计数器

import React, { Component } from 'react'
import PropTypes from 'prop-types'   //类型检查
import ReactDOM from 'react-dom'
import { createStore } from 'redux'
import { Provider, connect } from 'react-redux'

// 定义counter组件
class Counter extends Component {
  render() {
    const { value, onIncreaseClick } = this.props
    // const value = this.props.value
    return (
      <div>
        <span>{value}</span>
        <button onClick={onIncreaseClick}> +1</button>
      </div>
    )
  }
}
//对Counter组件接受的props进行类型检查
Counter.propTypes = {
  value: PropTypes.number.isRequired,   //要求数字类型,没有提供会警告
  onIncreaseClick: PropTypes.func.isRequired //要求函数类型
}

// Action  
const increaseAction = { type: 'increase' }

// Reducer   基于原有state根据action得到新的state
function counter(state = { count: 0 }, action) {
  const count = state.count
  switch (action.type) {
    case 'increase':
      return { count: count + 1 }
    default:
      return state
  }
}

// 根据reducer函数通过createStore()创建store
const store = createStore(counter)

//  将state映射到Counter组件的props
function mapStateToProps(state) {
  return {
    value: state.count
  }
}

//  将action映射到Counter组件的props
function mapDispatchToProps(dispatch) {
  return {
    onIncreaseClick: () => dispatch(increaseAction)
  }
}

//  传入上面两个函数参数,将Counter组件变为App组件
const App = connect(
  mapStateToProps,
  mapDispatchToProps
)(Counter)

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)

React使用G2图表数据可视化

在React项目中使用bizCharts,它的底层封装了g2

参考文档:https://bizcharts.net/product/bizcharts/gallery#LineChart

注意:**复制代码时注意版本号问题需要将@3.5.8与你安装的版本对应或者删除它:**在官网上bizCharts 3版本的图表代码中有这一行代码:

​ import { Chart, Axis, Tooltip, Geom, Legend, View } from ‘bizcharts@3.5.8’;

Immutable.js

参考文档:https://www.jianshu.com/p/0fa8c7456c15

React项目各个模块的思路

(1)商品管理中的添加和修改

1.使用的是同一个表单

2.通过点击添加/修改按钮时,当修改时会传入一个product对象,需要在render渲染之前,来判断是否传入了product,通过this.props.localtion.state获取传过来的product,在this中存入isUpdate,以便其他方法可以获取到(!!是将表达式强制转化为bool值的运算,运算结果为true或false,表达式是什么值,结果就是对应的bool值,不再取非不是取非再取非的意思),顺便把product存入this中

 componentWillMount() {
  //点击修改时会传入一个product
  const product = this.props.location.state
  this.isUpdate = !!product
   //在this中保存商品信息
   this.product = product || {}
  }

3.在修改中需要填充表单,需要在表单<Form.Item>中添加属性 initialValue={product.name},(product.name指该输入框或文本域中对应的值)

(2)上传图片

import { Upload, Modal, message } from 'antd';
import { PlusOutlined } from '@ant-design/icons';
import React from 'react'
import { reqDeletImg } from '../../api/index'
import PropType from 'prop-types'



class PicturesWall extends React.Component {
    static propType = {
        imgs: PropType.array
    }
    /* state = {
        previewVisible: false,
        previewImage: '',
        previewTitle: '',
        fileList: [
             {
              uid: '-1',
              name: 'image.png',
              status: 'done',
              url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
            } 
        ],
    }; */
    constructor(props) {
        super(props)
        //填充表单时需要初始化fileList的值
        let fileList = []
        const { imgs } = this.props
        if (imgs && imgs.length > 0) {
            fileList = imgs.map((img, index) => (
                {
                    uid: -index,
                    name: img,
                    status: 'done',
                    url: 'http://localhost:5000/upload/' + img,

                }))
        }
        this.state = {
            previewImage:'',
            previewVisible: false,
            fileList
        }

    }

    /**
     * 获取图片
     */
    getImgs = () => {
        //console.log('getImgs'+this.state.fileList)
        return this.state.fileList.map(file => file.name)
    }
    handleCancel = () => this.setState({ previewVisible: false });

    handlePreview = async file => {
        //console.log('handlePreview()'+JSON.stringify(file))
        //显示指定file的大图
        this.setState({
            previewImage: file.url || file.thumbUrl,
            previewVisible: true,
        });
    };

    handleChange = async ({ file, fileList }) => {
        //修正file的信息name、url

        if (file.status === 'done') {
            const result = file.response
            //console.log('file.response'+JSON.stringify(result))
            if (result.status === 0) {
                message.success('上传成功')
                const { name, url } = result.data
                //file赋值为最后上传的那张图片
                file = fileList[fileList.length - 1]
                file.name = name
                file.url = url
            } else {
                message.error('上传图片失败')
            }
        } else if (file.status === 'removed') { //删除图片
            const result = await reqDeletImg(file.name)
            if (result.status === 0) {
                message.success('删除成功')
            } else {
                message.error('删除失败')
            }
        }
        this.setState({ fileList })
    };

    render() {
        const { previewVisible, previewImage, fileList, previewTitle } = this.state;
        const uploadButton = (
            <div>
                <PlusOutlined />
                <div className="ant-upload-text">Upload</div>
            </div>
        );
        return (
            <div className="clearfix">
                <Upload
                    action="/manage/img/upload"
                    listType="picture-card"
                    name="image"
                    fileList={fileList}
                    onPreview={this.handlePreview}
                    onChange={this.handleChange}
                >
                    {fileList.length >= 8 ? null : uploadButton}
                </Upload>
                <Modal
                    visible={previewVisible}
                    title={previewTitle}
                    footer={null}
                    onCancel={this.handleCancel}
                >
                    <img alt="example" style={{ width: '100%' }} src={previewImage} />
                </Modal>
            </div>
        );
    }
}

export default PicturesWall
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值