npm isntall -g create-react-app
npm install -g yarn
create-react-app my-app
npm start
yarn start
Cannot find module ‘react-dev-utils/getPublicUrlOrPath’
npm update
npm install --save-dev react-dev-utils
const name = "xiaoxiaoran"
const age = 11
//const title = (JSX,name={name},age={age}
)
const title = (<h1 className="title" >JSX,name={name},age={age}<span /></h1>)
ReactDom.render(title, document.getElementById('root'))
const songs = [{ id: 1, name: 'song1' }, { id: 2, name: 'song2' }, { id: 3, name: 'song3' }]
const list = (<ul>{songs.map(item => <li key={item.id}> {item.name}</li>)}</ul>)
ReactDom.render(list, document.getElementById('root'))
import React from "react";
class Hello extends React.Component {
render() {
return 抽离到js文件中的类组件
}
}
export default Hello
import Hello from './js/Hello.js'
//const Hello = () => 函数组件
//function Hello() { return (函数组件) }
//class Hello extends React.Component { render() { return 类组件 } }
ReactDom.render(<Hello />, document.getElementById('root'))
// class App extends React.Component {
// handleClick() { alert('xiuxiu') }
// render() {
// return ()
// }
// }
function App() {
function handleClick() { alert('xiuxiu') }
return (<button onClick={handleClick}>click</button>)
}
ReactDom.render(<App />, document.getElementById('root'))
class App1 extends React.Component {
handleClick(e) {
e.preventDefault()
alert('阻止默认行为')
}
render() {
return (<a href="https://xiaoxiaoran.top" onClick={this.handleClick}>click</a>)
}
}
ReactDom.render(<App1 />, document.getElementById('root'))
class App2 extends React.Component {
state = { count: 0 }
f1() { this.setState({ count: this.state.count + 1 }) }
constructor() {
super()
this.state = { count: 100 }
// bind this指向实例
this.f1 = this.f1.bind(this)
}
render() {
return (
<div>
<h1>count={this.state.count}</h1>
{/* */}
{/* */}
<button onClick={this.f1} >+1</button>
</div>
)
}
}
ReactDom.render(<App2 />, document.getElementById('root'))
class App3 extends React.Component {
state = {
txt: '',
content: '',
isCheck: true
}
handleChange = e => {
const target = e.target
const value = target.type === 'checkbox' ? target.checked : target.value
const name = target.name
this.setState({
[name]: value
})
}
render() {
return (
<div>
<input name="txt" type="text" value={this.state.txt} onChange={this.handleChange} /><br />
<textarea name="content" value={this.state.content} onChange={this.handleChange} />
<input name="isCheck" type="checkbox" checked={this.state.isCheck} onChange={this.handleChange} />
</div>
)
}
}
ReactDom.render(<App3 />, document.getElementById('root'))
.title {
text-align: center;
}
.app {
width: 300px;
padding: 10px;
border: 1px solid #999;
}
.user {
width: 100%;
box-sizing: border-box;
margin-bottom: 10px;
}
.content {
width: 100%;
box-sizing: border-box;
margin-bottom: 10px;
}
.no-comment {
text-align: center;
margin-top: 30px;
}
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
class App extends React.Component {
// 初始化状态
state = {
comments: [
{ id: 1, name: 'jack', content: '沙发!!!' },
{ id: 2, name: 'rose', content: '板凳~' },
{ id: 3, name: 'tom', content: '楼主好人' }
],
// 评论人
userName: '',
// 评论内容:
userContent: ''
}
// 渲染评论列表:
renderList() {
const { comments } = this.state
if (comments.length === 0) { return <div className="no-comment">暂无评论,快去评论吧~</div> }
return (
<ul>
{comments.map(item => (
<li key={item.id}>
<h3>评论人:{item.name}</h3>
<p>评论内容:{item.content}</p>
</li>
))}
</ul>
)
}
// 处理表单元素值
handleForm = e => {
const { name, value } = e.target
this.setState({
[name]: value
})
}
// 发表评论:
addComment = () => {
const { comments, userName, userContent } = this.state
// 非空校验
if (userName.trim() === '' || userContent.trim() === '') {
alert('请输入评论人和评论内容')
return
}
// 将评论信息添加到state中
const newComments = [
{
id: Math.random(),
name: userName,
content: userContent
},
...comments
]
// 文本框的值如何清空? 要清空文本框只需要将其对应的state清空即可
this.setState({
comments: newComments,
userName: '',
userContent: ''
})
}
render() {
const { userName, userContent } = this.state
return (
<div className="app">
<div>
<input className="user" type="text" placeholder="请输入评论人" value={userName} name="userName" onChange={this.handleForm} />
<br />
<textarea className="content" cols="30" rows="10" placeholder="请输入评论内容" value={userContent} name="userContent" onChange={this.handleForm} />
<br />
<button onClick={this.addComment}>发表评论</button>
</div>
{/* 通过条件渲染决定渲染什么内容: */}
{this.renderList()}
</div>
)
}
}
// 渲染组件
ReactDOM.render(<App />, document.getElementById('root'))
class Hello extends React.Component {
render() {
console.log(this.props)
return (
<div>
<h1>props: {this.props.age} {this.props.name} </h1>
</div>
)
}
}
// 1 传递数据
ReactDOM.render(<Hello name="rose" age={19} />, document.getElementById('root'))
// 2 接收数据
const Hello = xiao => {
// xiao是一个对象
console.log(xiao)
return (
<div>
<h1>props:{xiao.name} {xiao.age} </h1>
</div>
)
}
// 1 传递数据
ReactDOM.render(<Hello name="jack" age={19} />, document.getElementById('root'))
class Hello extends React.Component {
// 推荐使用props作为constructor的参数!!
constructor(props) {
super(props)
// console.log(this.props)
console.log(props)
}
render() {
console.log('render:', this.props)
return (
<div>
<h1>props:{this.props.name} {this.props.colors}</h1>
</div>
)
}
}
ReactDOM.render(<Hello name="rose" age={19} colors={['red', 'green', 'blue']} fn={() => console.log('这是一个函数')} tag={<p>这是一个p标签</p>} />, document.getElementById('root'))
import React from 'react'
import ReactDOM from 'react-dom'
const App = props => {
console.log(props)
return (
<div>
<h1>组件标签的子节点:</h1>
{props.children}
</div>
)
}
ReactDOM.render(<App>我是子节点</App>, document.getElementById('root'))
import React from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'
const App = props => {
const arr = props.colors
const lis = arr.map((item, index) => <li key={index}>{item}</li>)
return <ul>{lis}</ul>
}
// 添加props校验
App.propTypes = {
colors: PropTypes.array
}
ReactDOM.render(
<App colors={['red', 'blue']} />,
document.getElementById('root')
)
import React from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'
const App = props => {
return (
<div>
<h1>props校验:</h1>
</div>
)
}
// 添加props校验
// 属性 a 的类型: 数值(number)
// 属性 fn 的类型: 函数(func)并且为必填项
// 属性 tag 的类型: React元素(element)
// 属性 filter 的类型: 对象({area: '上海', price: 1999})
App.propTypes = {
a: PropTypes.number,
fn: PropTypes.func.isRequired,
tag: PropTypes.element,
filter: PropTypes.shape({
area: PropTypes.string,
price: PropTypes.number
})
}
ReactDOM.render(<App fn={() => { }} />, document.getElementById('root'))
import React from 'react'
import ReactDOM from 'react-dom'
// 父组件
class Parent extends React.Component {
state = { xiao: 1 }
render() {
return (
<div className="parent">
父组件:
<Child name={this.state.xiao} />
</div>
)
}
}
// 子组件
const Child = temp => {
return (
<div className="child">
<p>子组件,接收到父组件的数据:{temp.name}</p>
</div>
)
}
ReactDOM.render(<Parent />, document.getElementById('root'))
import React from 'react'
import ReactDOM from 'react-dom'
// 父组件
class Parent extends React.Component {
state = { parentMsg: '' }
// 提供回调函数,用来接收数据
getChildMsg = data => {
console.log('接收到子组件中传递过来的数据:', data)
this.setState({ parentMsg: data })
}
render() {
return (
<div className="parent">
父组件:{this.state.parentMsg}
<Child getMsg={this.getChildMsg} />
</div>
)
}
}
// 子组件
class Child extends React.Component {
state = {
msg: '刷抖音'
}
handleClick = () => {
// 子组件调用父组件中传递过来的回调函数
this.props.getMsg(this.state.msg)
}
render() {
return (
<div className="child">
子组件:{' '}
<button onClick={this.handleClick}>点我,给父组件传递数据</button>
</div>
)
}
}
ReactDOM.render(<Parent />, document.getElementById('root'))
import React from 'react'
import ReactDOM from 'react-dom'
// 父组件
class Counter extends React.Component {
// 提供共享状态
state = { count: 0 }
// 提供修改状态的方法
onIncrement = () => { this.setState({ count: this.state.count + 1 }) }
render() {
return (
<div>
<Child1 count={this.state.count} />
<Child2 onIncrement={this.onIncrement} />
</div>
)
}
}
const Child1 = temp => { return <h1>计数器:{temp.count}</h1> }
const Child2 = temp => { return <button onClick={() => temp.onIncrement()}>+1</button> }
ReactDOM.render(<Counter />, document.getElementById('root'))
import React from 'react'
import ReactDOM from 'react-dom'
// 创建context得到两个组件
const { Provider, Consumer } = React.createContext()
class App extends React.Component {
render() {
return (
<Provider value="xiaoxiaoran">
<div className="app">
<Node />
</div>
</Provider>
)
}
}
const Node = props => {
return (
<div className="node">
<SubNode />
</div>
)
}
const SubNode = props => {
return (
<div className="subnode">
<Child />
</div>
)
}
const Child = props => {
return (
<div className="child">
<Consumer>{data => <span>我是value={data}</span>}</Consumer>
</div>
)
}
ReactDOM.render(<App />, document.getElementById('root'))
import React from 'react'
import ReactDOM from 'react-dom'
class App extends React.Component {
state = { count: 1 }
handleClick = () => {
// 此处,更新state
// 注意:异步更新数据的!!!
this.setState({ count: this.state.count + 1 })
console.log('count:', this.state.count) // 1
this.setState({ count: this.state.count + 1 })
console.log('count:', this.state.count) // 1
}
render() {
console.log('render')
return (
<div>
<h1>计数器:{this.state.count}</h1>
<button onClick={this.handleClick}>+1</button>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'))
import React from 'react'
import ReactDOM from 'react-dom'
class App extends React.Component {
state = { count: 1 }
handleClick = () => {
// 推荐语法:
// 注意:这种语法也是异步更新state的!
this.setState((state, props) => {
return {
count: state.count + 1 // 1 + 1
}
})
this.setState((state, props) => {
console.log('第二次调用:', state)
return {
count: state.count + 1
}
})
console.log('count:', this.state.count) // 1
}
render() {
return (
<div>
<h1>计数器:{this.state.count}</h1>
<button onClick={this.handleClick}>+1</button>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'))
import React from 'react'
import ReactDOM from 'react-dom'
class App extends React.Component {
state = {
count: 1
}
handleClick = () => {
this.setState(
(state, props) => {
return {
count: state.count + 1
}
},
// 状态更新后并且重新渲染后,立即执行:
() => {
console.log('状态更新完成:', this.state.count) // 2
console.log(document.getElementById('title').innerText)
document.title = '更新后的count为:' + this.state.count
}
)
console.log(this.state.count) // 1
}
render() {
return (
<div>
<h1 id="title">计数器:{this.state.count}</h1>
<button onClick={this.handleClick}>+1</button>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'))
import React from 'react'
import ReactDOM from 'react-dom'
// const element = Hello JSX!
const element = React.createElement(
'h1',
{
className: 'greeting'
},
'Hello JSX!'
)
console.log(element)
ReactDOM.render(element, document.getElementById('root'))
.app {
width: 800px;
padding: 20px;
}
.app-wrapper {
display: flex;
}
.parent {
flex: 1;
height: 300px;
background-color: skyblue;
}
.parent:first-child {
margin-right: 30px;
}
.parent-wrapper {
display: flex;
}
.child {
flex: 1;
height: 200px;
background-color: yellowgreen;
}
.child:first-child {
margin-right: 20px;
}
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
// 根组件 二叉树的先序遍历
class App extends React.Component {
state = {
color: '#369'
}
getColor() {
return Math.floor(Math.random() * 256)
}
changeBG = () => {
this.setState(() => {
return {
color: `rgb(${this.getColor()}, ${this.getColor()}, ${this.getColor()})`
}
})
}
render() {
console.log('根组件')
return (
<div className="app" style={{ backgroundColor: this.state.color }}>
<button onClick={this.changeBG}>根组件 - 切换颜色状态</button>
<div className="app-wrapper">
<Parent1 />
<Parent2 />
</div>
</div>
)
}
}
// ------------------------左侧---------------------------
class Parent1 extends React.Component {
state = {
count: 0
}
handleClick = () => {
this.setState(state => ({ count: state.count + 1 }))
}
render() {
console.log('左侧父组件')
return (
<div className="parent">
<h2>
左侧 - 父组件1
<button onClick={this.handleClick}>点我({this.state.count})</button>
</h2>
<div className="parent-wrapper">
<Child1 />
<Child2 />
</div>
</div>
)
}
}
class Child1 extends React.Component {
render() {
console.log('左侧子组件 - 1')
return <div className="child">子组件1-1</div>
}
}
class Child2 extends React.Component {
render() {
console.log('左侧子组件 - 2')
return <div className="child">子组件1-2</div>
}
}
// ------------------------右侧---------------------------
class Parent2 extends React.Component {
state = {
count: 0
}
handleClick = () => {
this.setState(state => ({ count: state.count + 1 }))
}
render() {
console.log('右侧父组件')
return (
<div className="parent">
<h2>
右侧 - 父组件2
<button onClick={this.handleClick}>点我({this.state.count})</button>
</h2>
<div className="parent-wrapper">
<Child3 />
<Child4 />
</div>
</div>
)
}
}
class Child3 extends React.Component {
render() {
console.log('右侧子组件 - 1')
return <div className="child">子组件2-1</div>
}
}
class Child4 extends React.Component {
render() {
console.log('右侧子组件 - 2')
return <div className="child">子组件2-2 </div>
}
}
ReactDOM.render(<App />, document.getElementById('root'))
import React from 'react'
import ReactDOM from 'react-dom'
// 生成随机数
class App extends React.Component {
state = { number: 0 }
handleClick = () => {
this.setState(() => {
return { number: Math.floor(Math.random() * 3) }
})
}
// 钩子函数
// 因为两次生成的随机数可能相同,如果相同,此时,不需要重新渲染
shouldComponentUpdate(nextProps, nextState) {
console.log('最新状态:', nextState, ', 当前状态:', this.state)
return nextState.number !== this.state.number
// 返回false,阻止组件重新渲染
}
render() {
console.log('render 执行了')
return (
<div>
<h1>随机数:{this.state.number}</h1>
<button onClick={this.handleClick}>重新生成</button>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'))
import React from 'react'
import ReactDOM from 'react-dom'
// 生成随机数
class App extends React.Component {
state = {
number: 0
}
handleClick = () => {
this.setState(() => {
return {
number: Math.floor(Math.random() * 3)
}
})
}
render() {
// console.log('render')
return (
<div>
<NumberBox number={this.state.number} />
<button onClick={this.handleClick}>重新生成</button>
</div>
)
}
}
class NumberBox extends React.Component {
shouldComponentUpdate(nextProps) {
console.log('最新props:', nextProps, ', 当前props:', this.props)
// 如果前后两次的number值相同,就返回false,不更新组件
return nextProps.number !== this.props.number
}
render() {
console.log('子组件中的render')
return <h1>随机数:{this.props.number}</h1>
}
}
ReactDOM.render(<App />, document.getElementById('root'))
import React from 'react'
import ReactDOM from 'react-dom'
// 生成随机数
class App extends React.PureComponent {
state = {
number: 0
}
handleClick = () => {
this.setState(() => {
return {
number: Math.floor(Math.random() * 2)
}
})
}
// render方法调用并不意味着浏览器中的重新渲染!!!
// render方法调用仅仅说明要进行diff
render() {
const el = (
<div>
<h1>随机数:</h1>
<p>{this.state.number}</p>
<button onClick={this.handleClick}>重新生成</button>
</div>
)
console.log(el)
return el
}
}
ReactDOM.render(<App />, document.getElementById('root'))
本案例粘贴于 github
// import { BrowserRouter as Router, Route, Routes, Link } from 'react-router-dom'
import { HashRouter as Router, Routes, Route } from 'react-router-dom';
import Home from './containers/Home/index';
import City from './containers/City/index';
import Earth from './containers/Earth/index';
import Demo from './containers/Demo/index';
import Lunar from './containers/Lunar/index';
import Cell from './containers/Cell/index';
import Car from './containers/Car/index';
import Zelda from './containers/Zelda/index';
import Metaverse from './containers/Metaverse/index';
import SegmentFault from './containers/SegmentFault/index';
import Diamond from './containers/Diamond/index';
import Human from './containers/Human/index';
import Olympic from './containers/Olympic/index';
function App() {
return (
<div className="App">
<Router>
<Routes>
<Route element={<Home />} path="/" />
<Route element={<City />} path="/city" />
<Route element={<Earth />} path="/earth" />
<Route element={<Demo />} path="/demo" />
<Route element={<Lunar />} path="/lunar" />
<Route element={<Cell />} path="/cell" />
<Route element={<Car />} path="/car" />
<Route element={<Zelda />} path="/zelda" />
<Route element={<Metaverse />} path="/metaverse" />
<Route element={<SegmentFault />} path="/segmentfault" />
<Route element={<Diamond />} path="/diamond" />
<Route element={<Human />} path="/human" />
<Route element={<Olympic />} path="/olympic" />
</Routes>
</Router>
</div>
);
}
export default App;
import React from 'react';
import Paper from '@mui/material/Paper';
import { styled } from '@mui/material/styles';
import Box from '@mui/material/Box';
import MediaCard from '../../components/MediaCard/index';
import Grid from '@mui/material/Grid';
import cityImage from './images/city.png';
import panoramicImage from './images/panoramic.png';
import metaImage from './images/meta.png';
import earthImage from './images/earth.png';
import cellImage from './images/cell.png';
import lunarImage from './images/lunar.png';
import zeldaImage from './images/zelda.png';
import zeldaMapImage from './images/zelda_map.png';
import scanImage from './images/scan.png';
import carImage from './images/car.png';
import developingImage from './images/developing.png';
import segmentFaultImage from './images/segmengfault.png';
import humanImage from './images/human.png';
import olympicImage from './images/olympic.png';
import './index.css';
const Item = styled(Paper)(({ theme }) => ({
...theme.typography.body2,
padding: theme.spacing(1),
textAlign: 'center',
color: theme.palette.text.secondary,
}));
const workList = [
{
link: '#/city',
title: '数字城市',
description: ' 3D数字城市 【⚠优化中】',
image: cityImage,
three: true
},
{
link: 'https://dragonir.github.io/3d-meta-logo/',
title: '脸书Meta元宇宙Logo',
description: ' Three.js + Blender 实现炫酷的Facebook元宇宙Logo.',
image: metaImage,
three: true
},
{
link: '#/olympic',
title: '2022冬奥会3D趣味页面',
description: '一只萌萌的冰墩墩送给大家!',
image: olympicImage,
three: true
},
{
link: 'https://dragonir.github.io/3d-panoramic-vision/',
title: '全景侦探小游戏',
description: '️ 使用Three.js全景功能实现侦探小游戏。',
image: panoramicImage,
three: true
},
{
link: '#/lunar',
title: '虎年春节创意',
description: ' 2022虎虎生威!',
image: lunarImage,
three: true
},
{
link: '#/segmentfault',
title: 'SegmentFault突破1000粉纪念',
description: ' 1000+ followers !',
image: segmentFaultImage,
three: true
},
{
link: '#/human',
title: 'Metahuman',
description: ' 元宇宙数字人类【⚠优化中】',
image: humanImage,
three: true
},
{
link: '#/earth',
title: '地球',
description: ' 尽情探索3D Low Poly数字地球吧!【⚠优化中】',
image: earthImage,
three: true
},
{
link: '#/cell',
title: '动植物细胞结构',
description: ' 可以查看动物细胞和植物细胞的内部组成结构。【⚠优化中】',
image: cellImage,
three: true
},
{
link: 'https://dragonir.github.io/zelda-map/',
title: '塞尔达:旷野之息地图',
description: ' 在地图上标记神庙、查询回忆点!',
image: zeldaMapImage,
},
{
link: 'https://dragonir.github.io/h5-scan-qrcode/',
title: '浏览器扫码',
description: ' 使用原生浏览器就可以在h5页面实现扫码功能了,试试看!',
image: scanImage,
},
{
link: '#/car',
title: 'Lamborghini Centenario LP-770',
description: '车辆模型展示【⚠优化中】',
image: carImage,
three: true
},
{
link: '#/zelda',
title: '塞尔达:旷野之息3D',
description: ' 林克【⚠优化中】',
image: zeldaImage,
three: true
},
{
link: '#/',
title: '远航:无尽的拉格朗日',
description: '开发中...',
image: developingImage,
three: true
},
{
link: '#/',
title: '探索:无人深空',
description: '开发中...',
image: developingImage,
three: true
},
{
link: '#/',
title: '着陆:失落的星球',
description: '开发中...',
image: developingImage,
three: true
},
{
link: '#/',
title: '航巡:迷失在黑洞',
description: '开发中...',
image: developingImage,
three: true
}
];
export default class Home extends React.Component {
render () {
return (
<div className="home" style={{ padding: '24px'}}>
<Box>
<h1 className="page_title">dragonir's work list</h1>
</Box>
<Box sx={{ width: '100%' }} style={{ maxWidth: '1200px', margin: 'auto' }}>
<Grid container rowSpacing={1} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
{workList.map((item, index) => (
<Grid item xs={12} sm={6} md={4} key={index}>
<Item elevation={0} className="grid_item">
{item.three ? (<i className="three_logo"></i>) : '' }
<MediaCard link={item.link} title={item.title} image={item.image} description={item.description} />
</Item>
</Grid>
))}
</Grid>
</Box>
</div>
)
}
}