19 RN之Hook重写项目

31 阅读2分钟

1.1 设计哲学演进

// 传统Class组件 vs Hooks范式
class Counter extends React.Component {
  state = { count: 0 }          // 状态管理受限
  componentDidMount() {         // 生命周期割裂
    document.title = `Count: ${this.state.count}`
  }
  componentDidUpdate() {
    document.title = `Count: ${this.state.count}`
  }
}

function Counter() {
  const [count, setCount] = useState(0)  // 线性状态管理
  useEffect(() => {                      // 逻辑聚合
    document.title = `Count: ${count}`
  }, [count])                            // 精准依赖控制
}

1.2 生命周期映射表(企业级实践)

Class 生命周期Hook 实现方案典型场景注意事项
constructoruseState惰性初始化大数据量初始化避免直接计算复杂初始值
componentDidMountuseEffect(fn, [])订阅事件/初始化请求清理函数必须返回
componentDidUpdateuseEffect(fn, [deps])依赖项变化处理精确控制依赖数组
shouldComponentUpdateReact.memo + useMemo复杂组件渲染优化避免过度优化
getDerivedStateFromPropsuseState + useEffectProps驱动状态更新使用useDerivedState自定义Hook

1.3 渐进式重构策略

// 新旧组件共存方案
class LegacyComponent extends React.Component {
  // 原有逻辑...
}

function NewComponent() {
  const [state] = useState(/*...*/)
  useEffect(/*...*/)
  
  return (
    <LegacyComponent 
      {...props}
      onUpdate={/* 桥接逻辑 */}
    />
  )
}

第二章 核心Hooks深度解析

2.1 useState

// Tab.tsx 复杂状态管理
type NavigationState = {
  routes: Array<{ key: string; title: string }>
  index: number
}

const [navState, setNavState] = useState<NavigationState>(() => ({
  routes: [
    { key: 'dashboard', title: '控制台' },
    { key: 'analytics', title: '分析' }
  ],
  index: sessionStorage.getItem('lastTabIndex') || 0
}))

// 安全更新模式
const updateIndex = (newIndex: number) => {
  setNavState(prev => ({
    ...prev,
    index: Math.max(0, Math.min(newIndex, prev.routes.length - 1))
  }))
}

2.2 useEffect全场景指南

// Navigator.tsx 路由监听最佳实践
const navigation = useNavigation()

useEffect(() => {
  const subscription = navigation.addListener('state', handleStateChange)
  
  const timer = setInterval(() => {
    analytics.sendHeartbeat()
  }, 5000)

  return () => {
    subscription.remove()
    clearInterval(timer)
    analytics.flush()
  }
}, [navigation, analytics]) // 严格依赖声明

// 竞态处理模式
useEffect(() => {
  let isCurrent = true
  fetchData().then(data => {
    if (isCurrent) setData(data)
  })
  return () => { isCurrent = false }
}, [query])

2.3 useRef高级应用

// BarrageItem.tsx 动画与DOM操作
const ref = useRef<Animated.View>(null)
const startPos = useRef(new Animated.Value(0)).current

useLayoutEffect(() => {
  Animated.timing(startPos, {
    toValue: 1,
    duration: 300,
    useNativeDriver: true
  }).start()
}, [])

const handleLayout = useCallback(() => {
  ref.current.measure((x, y) => {
    collisionDetection.registerPosition(x, y)
  })
}, [])

return <Animated.View 
  ref={ref} 
  onLayout={handleLayout}
  style={{ transform: [{ translateX: startPos }] }}
/>

第三章 性能优化体系

3.1 渲染优化矩阵

// SliderEntry.tsx 记忆化优化
const SliderEntry = React.memo(({ data }: Props) => {
  const formattedDate = useMemo(
    () => formatDate(data.timestamp, 'YYYY-MM-DD HH:mm'),
    [data.timestamp]
  )

  const handlePress = useCallback(() => {
    navigation.navigate('Detail', { id: data.id })
  }, [data.id])

  return (
    <Touchable onPress={handlePress}>
      <Text>{formattedDate}</Text>
    </Touchable>
  )
})

3.2 Redux性能优化

// HomeTabs.tsx 现代Redux实践
const dispatch = useDispatch()
const { channels, loading } = useSelector((state: RootState) => ({
  channels: selectFilteredChannels(state),
  loading: state.loading.effects.channels.fetch
}), shallowEqual)

// Reselect优化selector
const selectFilteredChannels = createSelector(
  [(state: RootState) => state.channels.data],
  (channels) => channels.filter(c => c.isActive)
)

第四章 自定义Hook开发规范

4.1 生命周期模拟Hook

// useDerivedState.ts - 替代getDerivedStateFromProps
function useDerivedState<T>(props: T, compute: (prev?: T) => T): [T, Dispatch<SetStateAction<T>>] {
  const [state, setState] = useState(() => compute(props))
  
  useLayoutEffect(() => {
    if (!Object.is(props, state)) {
      setState(compute(props))
    }
  }, [props])

  return [state, setState]
}

// 使用案例
const [derivedState] = useDerivedState(props, (prevProps) => {
  return props.value !== prevProps?.value 
    ? calculateState(props.value)
    : prevState
})

4.2 复杂状态管理Hook

// useUndoableState.ts 可撤销状态
function useUndoableState<T>(initialValue: T) {
  const [state, setState] = useState(initialValue)
  const [history, setHistory] = useState<T[]>([])
  const [pointer, setPointer] = useState(-1)

  const undo = useCallback(() => {
    setPointer(p => (p > 0 ? p - 1 : p))
  }, [])

  const redo = useCallback(() => {
    setPointer(p => (p < history.length - 1 ? p + 1 : p))
  }, [history])

  const updateState = useCallback((newValue: T) => {
    setHistory(prev => [...prev.slice(0, pointer + 1), newValue])
    setPointer(p => p + 1)
    setState(newValue)
  }, [pointer])

  return [state, updateState, { undo, redo, history }] as const
}