react

react 中子组件中调用父组件的方法,在传递的过程中 this 指向会发生变化,从父组件中传一个 this

// 父组件
<Child formViewEvent={(option, form) => this.formViewEvent(option, form, this)} />

// 子组件
<Button onClick={formViewEvent(btn, formData)}>
	{btn.title}
</Button>

安装

# 脚手架起一个react项目
npm install -g create-react-app
create-react-app react-mobx

bug

Minified React error #200; id 或者 class 名写错

react 组件

/**
ReactDom.render(标签或者组件(jsx对象), 要挂载的dom节点)
ReactDOM.render(<App />, document.getElementById('root'))
注:要挂载的dom节点不能是 document.body
组件和函数:重复的逻辑。通过给组件传人不同的参数,从而显示不同的形态。复杂的组件可以通过简单的组件构成。
*/

// 创建组件
const test = React.createClass({
    render: function() {
        // return 一个小括号
        return <div>abc</div>
    },
})

// 挂载组件
ReactDOM.render(<test />, document.getElementById('root'))

// 拿到父组件传过来的值, this.props.targetVal
const test = React.createClass({
    render: function() {
        // 大括号表示变量
        return <div>{this.props.targetVal}</div>
    },
})
ReactDOM.render(<test targetVal="hi, abc" />, document.getElementById('root'))

// this.props.children, 通过 {...this.props} 传递
const test = React.createClass({
    const style = {
        padding: 10,
        margin: this.props.marginVal
    }
    render: function() {
        return <div style={style}>{this.props.children}</div>
    },
})
ReactDOM.render(<test marginVal="{10}" {...this.props} />, document.getElementById('root'))

// 组件传递就是从父到子,不能跨级
// 组件的状态,state,this.setState
const test = React.createClass({
    // state设置的生命周期
    state: () => {
        // 默认会注入相应的生命周期getInitialState
    },
    getInitialState: function() {
        return {
            num: 0
        }
    },
    action: function() {
        this.setState({
            num: this.state.num + 1
        })
    },
    componentDidMount: function() {
        setInterval(this.action, 1000)
    },
    render: function() {
        return <div>{this.state.num}</div>
    },
})

// 事件
const test = React.createClass({
    action: function(e) {
        if(e.shiftKey === true) {
            console.log('shift 键被按下')
        }
    },
    render: function() {
        return <div onClick={this.action}>abc</div>
    },
})
// 生命周期
getDefaultProps: function() {}
getInitialState: function() {}

react 相应用户输入

// 把组件赋值给一个变量
const test = <test name="aaa" />
ReactDOM.render(<div>{test}</div>, document.getElementById('root'))
// 等同于 ReactDOM.render(<div><test name="aaa" /></div>, document.getElementById('root'))

// 标签内可以直接赋值一个函数
function show() {
    const colors = ['#aaa', '#f00', '#0f0']
    const ran = Math.floor(Math.randow() * colors.length)
    return <test bgColor={color[ran]} />
}
ReactDOM.render(<div>{show()}</div>, document.getElementById('root'))

// 循环组件
// key 跟虚拟dom有关,循环必须要有,而且唯一
function show() {
    const colors = ['#aaa', '#f00', '#0f0']
    const renderData = []
    for (let i = 0; i < colors.length; i++) {
        const ran = Math.floor(Math.randow() * colors.length)
        renderData.push(<test bgColor={color[ran]} key={i + colors[ran]} />)
    }
    return renderData
}
ReactDOM.render(<div>{show()}</div>, document.getElementById('root'))

// DOM 模型操作
// 获取输入框里的值
const test = React.createClass({
    state: () => {
        inputVal: '',
        color: ''
    },
    getVal: function(e) {
        this.setState({
            inputVal: e.target.value
        })
    },
    setColor: function(e) {
        this.setState({
            color: this.state.inputVal
        })
        this._input.value = ""
        this._input.focus()
        // 去掉默认时间,不要把from表单的数据打成一个包发给服务器
        e.preventDefault()
    }
    render: function() {
        const style = {
            backgroundColor: this.state.bgColor
        }
        const self = this
        return <div style={style}>
            <form onSubmit={this.setColor}>
                <input onChange={this.getVal} ref={function(el) {
                    // el就是 input 对象, 传出去才能调用
                    self._input = el
                }}/>
                <button type="submit">提交</button>
            </form>
        </div>
    },
})

react 综合运用

其他

create-react-app 生成的项目文件解读

// <code>code 标签中间写代码</code>

// 引入一个 svg 图片,直接放在 img 标签的 src 即可
// import logo from './logo.svg';
// <img src={logo} alt="logo" />

// 引入 css 文件,标签上用 className 直接用
// import './App.css'

// <header className="App-header" />

// react 定义 Component 组件
// react-dom 把定义好的组件映射到 dom 上
// react 定义 Component 组件
import React, { Component } from 'react'
class App extends Component {
	render() {
		return <div className="App" />
	}
}
export default App

// react-dom 把定义好的组件映射到 dom 上
import ReactDOM from 'react-dom'
import App from './App'
ReactDOM.render(<App />, document.getElementById('root'))

react 中事件必须不能执行,即不能带括号,否则就要在里面写一个箭头函数

<button
	onClick={() => {
		this.props.nav.addMenus(+new Date())
	}}
>
	添加menus
</button>

react 高阶

context && contextType

能够让数据在组件树中传递而不必一级一级手动传递

context: <Provider> <Consumer> createContext(defaultValue)

// index.jsx(创建,发起)
const BatteryContext = createContext()
render() {
    return (
        <BatteryContext.Provider value={60}>
            <app></app>
        </BatteryContext.Provider>
    )
}
// 子组件(应用)

render() {
    return <BatteryContext.Consumer value={60}>
            {
                data => <div>data</div>
            }
        </BatteryContext.Consumer>
}

// 两个的话就两级嵌套,但是一般只用一个就好
<AContext.Provider value={60}>
<BContext.Provider value={60}>
    <app></app>
</BContext.Provider>
</AContext.Provider>

<AContext.Consumer>
    {
        a => (
            <AContext.Consumer>
                {
                    b => <div>{`${a}_${b}`}</div>
                }
            </AContext.Consumer>
        )
    }
</AContext.Consumer>

// 如果只有一个context,子组件(应用)可以用 contextType 代替Consumer

class Child extends Component {
    static contextType = BatteryContext
    render() {
        const data = this.context
        return <div>{data}</div>
    }
}

hooks redux

redux 原则 单一数据源:应用程序的所有数据都挂载在同一对象下面,方便管理。同一信息量的数据只有一份,避免不同步。 状态不可变:修改数据的前后,数据源不再是同一个对象,可以实现应用程序状态的保存,实现时间旅行的功能。可以避免不按照规定去直接修改数据的行为。 纯函数修改状态:纯函数是没有副作用,不依赖外部变量,同样的输入产生同样的输出。可以精确实现对数据的修改行为。

  • 并没有向任何子组件传递,就不用 useCallback
  • 用 map 的时候应该用单独的组件把 item 渲染出来,这样才不至于当 list 发生变化的时候所有的 item 都重新渲染一遍
  • useEffect 副作用,当某个 useState 中的值发生变化的时候执行,如果项目中只用执行一次,那么,第二个参数设置为空数组。
  • useEffect 的执行是有顺序的
  • 函数组件用 memo 包裹起来 memo(function() {})
const inputRef = useRef()

const onSubmit = (e) => {
    e.preventDefault()
    const newText = inputRef.current.value.trim()
    addTodo(newText)
    inputRef.current.value = ""
}
<form onSubmit={onSubmit}>
    <input ref={inputRef}>
</from>

用 const [todo, setTodo] = useState([]) 当添加删除 todolist 的时候,不同的操作调用的是同一种方法 setTodos 现在有一种新的写法,用一种纯对象的方法描述对数据的操作

// 整个对象称之为action,然后让每个action都经过一个中心节点函数,在这个函数里面集中处理一些副作用,或者连带更新的行为
{
    // 描述对数据进行了怎样的操作
    type: 'add',
    // 用来描述执行这个操作需要什么额外的参数,可以为空
    payload: todo
}

// 中心函数叫:dispatch
// dispatch如果需要传递到子组件中要用一个useCallback包裹起来, 除了setTodo没有对任何参数进行以来,第二个参数是空数组
const dispatch = useCallback((action) => {
    const { type, payload } = action
    switch(type) {
        case 'set':
            setTodo(payload)
            break;
        case 'add':
            setTodo(todo => [...todo, payload])
            break;
        default:
    }
}, [])

// 调用
useEffect(() => {
    dispatch({type: 'set', payload: todo})
}, [])

高阶组件

高阶函数:函数可以作为参数被传递,函数可以作为返回值被输出 高阶组件:接收一个组件作为参数并返回一个新组件的函数,高阶组件是一个函数,并不是一个组件

// 函数可以作为参数被传递
// 数组中: some(),map(),forEach(),filter() 都是
setTimeout(() => {
	console.log(1)
}, 1000)

$.get('/api/get', function() {
	console.log('OK')
})

// 函数可以作为返回值被输出
function foo(x) {
	return function() {
		return x
	}
}

// 高阶组件
import React, { Component } from 'react'
function Wrap(Content) {
	return class A extends Component {
		render() {
			return (
				<div>
					<header>公共部分</header>
					<main>
						<Content />
					</main>
				</div>
			)
		}
	}
}
export default Wrap

// 应用
import React, { Component } from 'react'
import Wrap from './wrap'
class A extends Component {
	render() {
		return <div>组件A</div>
	}
}
export default Wrap(A)

// es6语法,装饰器
// 安装依赖:npm i -D babel-preset-stage-2 babel-preset-react-native-stage-0
// .babelrc配置:{"presets": ["react-native-stage-0/decorator-support"]}
import React, { Component } from 'react'
import wrap from './wrap'
@wrap
class A extends Component {
	render() {
		return <div>组件A</div>
	}
}
export default A

代理方式的高阶组件

返回的新组件类直接继承自 React.Component 类,新组件扮演的角色传人参数组件的一个代理, 在新组件的 render 函数中,将被包裹组件渲染出来,除了高阶组件自己要做的工作,其余功能全都转手给了被包裹的组件

继承方式的高阶组件

采用

右键列表

方法一:
onContextMenu: (event) => {
console.log("鼠标右击了 1")
},

方法二:
onMouseUp:(e)=>{
if (e.button===2) {
console.log('鼠标右击了 2')
}
},

全局阻止浏览器默认事件(鼠标右击事件等)

document.oncontextmenu = function(){
return false;
}