创建项目
create-react-app my-app
创建项目cd my-app
npm start
启动npm run build
打包npm test
测试npm run eject
暴露react
配置(不可逆转)
第一阶段
组建的render方法
注意 必须要用一个外层元素把内容进行包裹:
render () {
return (
<div>
<div>{word}</div>
</div>
)
}
表达式插入
render () {
const word = 'hello word'
return (
<div>
<div>{word}</div>
</div>
)
}
函数表达式返回
render () {
return (
<div>
<div>{(function () { return 'hello word'})()}</div>
</div>
)
}
<font color="red">
注意:</font> {}
内可以放任何 JavaScript 的代码,包括变量、表达式计算、函数执行等等。
表达式也可以用在标签的属性上
render () {
const className = 'hello'
return (
<div className={className}>
<h1>React</h1>
</div>
)
}
同时也支持条件判断,双目,三目这些一些
组件的组合、嵌套和组件树
class Main extends Component {
render() {
return (
<div>这是content</div>
)
}
}
class Footer extends Component {
render() {
return (
<div>这是尾部</div>
)
}
}
class App extends Component {
render() {
return (
<div>
<Main />
<Footer />
</div>
)
}
}
事件监听
class Header extends Component {
handleClickTitle(e) {
console.log('test click')
console.log('e', e.target)
}
render() {
return (
<div>
<Title />
<h2 onClick={this.handleClickTitle}>这是头部</h2>
</div>
)
}
}
如果你想在事件函数当中使用当前的实例,你需要手动地将实例方法 bind
到当前实例上再传入给 React.js。
class Main extends Component {
handleClickContent(word, e) {
console.log(this, word)
}
render() {
// 绑定this
return (
<div onClick={this.handleClickContent.bind(this, 'hello')}>这是content</div>
)
}
}
组件的 state 和 setState
class Footer extends Component {
constructor() {
super()
this.state = {
support: false,
}
}
handleClick() {
this.setState({
support: !this.state.support
})
// setState 的时候,React.js 并不会马上修改 state。而是把这个对象放到一个更新队列里面,稍后才会从队列当中把新的状态提取出来合并到 state 当中
console.log(this.state.support)
}
// setState 第二种使用方式
add() {
// this.setState({count : 0}) // this.state.count 还是 undefined
// this.setState({count : this.state.count + 1}) // undefined + 1 null
this.setState((prevState) => {
return {count: 0}
})
this.setState((prevState) => {
return {count: prevState.count + 1}
})
this.setState((prevState) => {
console.log(prevState.count)
return { count: prevState.count + 2 } // 上一个 setState 的返回是 count 为 1,当前返回 3
})
}
render() {
return (
<div>
这是尾部
<button onClick={this.handleClick.bind(this)}>
{this.state.support ? '取消' : '支持'}
</button>
<button onClick={this.add.bind(this)}>+1</button>
</div>
)
}
}
配置组件的 props
class Support extends Component {
// 和vue一样, props不可变
// 默认配置 defaultProps
static defaultProps = {
left: '支持',
right: '反对'
}
constructor() {
super()
this.state = {
}
}
render () {
return (
<div className="support">
<button>{this.props.left}</button>
<button>{this.props.right}</button>
</div>
)
}
}
同时也可以往props
里面传入函数
列表渲染
const users = [
{ username: 'Jerry', age: 21, gender: 'male' },
{ username: 'Tony', age: 22, gender: 'male' },
{ username: 'Lily', age: 19, gender: 'female' },
{ username: 'Lucy', age: 20, gender: 'female' }
]
class User extends Component {
render() {
const {user} = this.props
return (
<div>
<div>姓名:{user.username}</div>
<div>年龄:{user.age}</div>
<div>性别:{user.gender}</div>
</div>
)
}
}
class Main extends Component {
render() {
// 绑定this
return (
<div>
{users.map((user, idx) => <User key={idx} user={user} />)}
</div>
)
}
}
key
必须是每个元素唯一的标识。一般来说,key
的值可以直接后台数据返回的 id
,因为后台的 id
都是唯一的。
向父组件传递数据
// 子组件
class CommentInput extends Component {
constructor() {
super()
this.state = {
username: '',
content: ''
}
}
/**
* React.js 当中必须要用 setState 才能更新组件的内容,
* 所以我们需要做的就是:监听输入框的 onChange 事件,然后获取到用户输入的内容,
* 再通过 setState 的方式更新 state 中的 username,这样 input 的内容才会更新
*/
handleUsernameChange(event) {
this.setState({
username: event.target.value
})
}
handleContentChange(event) {
this.setState({
content: event.target.value
})
}
handleSubmit() {
/**
* CommentInput 如何向 CommentApp 传递的数据?
* 父组件 CommentApp 只需要通过 props 给子组件 CommentInput 传入一个回调函数。
* 当用户点击发布按钮的时候,CommentInput 调用 props 中的回调函数并且将 state 传入该函数即可。
*/
if (this.props.onSubmit) {
const {username, content} = this.state
this.props.onSubmit({username, content})
}
this.setState({content: ''})
}
render() {
return (
<div className="comment-input">
<div className='comment-field'>
<span className='comment-field-name'>用户名:</span>
<div className='comment-field-input'>
<input
onChange={this.handleUsernameChange.bind(this)}
value={this.state.username} />
</div>
</div>
<div className='comment-field'>
<span className='comment-field-name'>评论内容:</span>
<div className='comment-field-input'>
<textarea
onChange={this.handleContentChange.bind(this)}
value={this.state.content} />
</div>
</div>
<div className='comment-field-button'>
<button onClick={this.handleSubmit.bind(this)}>
发布
</button>
</div>
</div>
)
}
}
父组件接收
class CommentApp extends Component {
handleSubmitComment (comment) {
console.log(comment)
}
render() {
return (
<div className="wrapper">
<CommentInput
onSubmit={this.handleSubmitComment.bind(this)} />
</div>
)
}
}
第二阶段
挂载阶段的组件生命周期
class Header extends Component {
constructor() {
super()
console.log('constructor')
}
componentWillMount() {
console.log('component will mount')
}
componentDidMount() {
console.log('component did mount')
}
render() {
console.log('render')
return (
<div>
<h2>这是头部</h2>
</div>
)
}
componentWillUnmount() {
console.log('component will unmount')
}
}
执行顺序
constructor
component will mount
render
component did mount
class App extends Component {
constructor() {
super()
this.state = {
isShowHeader: true,
}
}
handleShowOrHide() {
this.setState({
isShowHeader: !this.state.isShowHeader
})
}
render() {
return (
<div>
<p>时钟</p>
{this.state.isShowHeader ? <Header /> : null}
<button onClick={this.handleShowOrHide.bind(this)}>{this.state.isShowHeader ? '隐藏' : '显示'}</button>
<Main />
</div>
)
}
}
当组件销毁的时候会执行componentWillUnmount
这个钩子
ref 和 React.js 中的 DOM 操作
class Main extends Component {
componentDidMount() {
this.input.focus()
}
render() {
return (
<input ref={(input) => this.input = input} />
)
}
}
这里是拿到input
的引用,让input
自动获取焦点
props.children 和容器类组件
class Card extends Component {
render() {
return (
<div className="card">
<div className="card-content">
{this.props.children}
</div>
</div>
)
}
}
class App extends Component {
render() {
return (
<div>
<Card>
<h2>React.js 小书</h2>
<div>开源、免费、专业、简单</div>
订阅:<input />
</Card>
<Main />
</div>
)
}
}
dangerouslySetHTML 和 style 属性
动态的 HTML 内容
class Main extends Component {
handleClickContent(word, e) {
console.log(this, word)
}
// dangerouslySetInnerHTML 可以让我们设置动态设置元素的 innerHTML
constructor() {
super()
this.state = {
content: '<h1>hello React</h1>',
color: 'red'
}
}
render() {
// 需要把 CSS 属性变成一个对象再传给元素
return (
<div style={{fontSize: '20px', color: this.state.color}} dangerouslySetInnerHTML={{__html: this.state.content}}></div>
)
}
}
PropTypes 和组件参数验证
先要安装一个 React 提供的第三方库 prop-types
npm install --save prop-types
示例
import PropTypes from 'prop-types'
class Comment extends Component {
// 验证
static propTypes = {
comment: PropTypes.object
}
render () {
const { comment } = this.props
return (
<div className='comment'>
<div className='comment-user'>
<span>{comment.username} </span>:
</div>
<p>{comment.content}</p>
</div>
)
}
}
class App extends Component {
render() {
return (
<div>
<Comment comment={{username: 'bie', content: '哈哈哈哈'}} />
</div>
);
}
}
这时候如果再往里面传入数字,浏览器就会报错.