gpt4 book ai didi

javascript - 如何为整个应用程序创建包装器组件?

转载 作者:行者123 更新时间:2023-11-29 15:08:34 26 4
gpt4 key购买 nike

我正在尝试为我的 React 应用程序添加一些分析跟踪。基本上只是使用组件添加全局事件监听器,然后在该组件中适本地处理事件。

我想将我的整个应用程序包装在这个组件中并让它接收 componentWillUpdate prop 更改,以便我可以使用 prop.location 对页面更改使用react.我的问题是我不知道如何设置我的包装器组件来执行此操作。我知道 HOC 的概念可以帮助包装一个组件,我已经测试过它可以工作,但我希望它成为一个更通用和全局的组件。

Tracker.js

import PropTypes from "prop-types"
import * as React from "react"
import { connect } from "react-redux"

import TrackingManager from './TrackingManager'
import ScriptManager from "./ScriptManager"
import { isLeftClickEvent } from "../utils/Utils"

const trackingManager = new TrackingManager()

const config = {
useTagManager: true,
tagManagerAccount: 'testCccount',
tagManagerProfile: 'testProfile',
tagManagerEnvironment: 'dev'
}

/**
* compares the locations of 2 components, mostly taken from:
* http://github.com/nfl/react-metrics/blob/master/src/react/locationEquals.js
*
* @param a
* @param b
* @returns {boolean}
*/
function locationEquals(a, b) {
if (!a && !b) {
return true;
}
if ((a && !b) || (!a && b)) {
return false;
}

return (
a.pathname === b.pathname && a.search === b.search && a.state === b.state
);
}

/**
* Tracking container which wraps the supplied Application component.
* @param Application
* @param beforeAction
* @param overrides
* @returns {object}
*/
const track = Application =>
class TrackingContainer extends React.Component {
constructor(props) {
super(props)
}

componentDidMount() {
this._addClickListener()
this._addSubmitListener()
}

componentWillUnmount() {
// prevent side effects by removing listeners upon unmount
this._removeClickListener()
this._removeSubmitListener()
}

componentDidUpdate(prevProps) {
// if and only if the location has changed we need to track a
// new pageview
if (!locationEquals(this.props.location, prevProps.location)) {
this._handlePageView(this.props)
}
}


_addClickListener = () => {
// bind to body to catch clicks in portaled elements (modals, tooltips, dropdowns)
document.body.addEventListener("click", this._handleClick)
}

_removeClickListener = () => {
document.body.removeEventListener("click", this._handleClick)
}

_addSubmitListener = () => {
document.body.addEventListener("submit", this._handleSubmit)
}

_removeSubmitListener = () => {
document.body.removeEventListener("submit", this._handleSubmit)
}

_handleSubmit = event => {
console.log(event.target.name)
}

_handleClick = event => {
// ensure the mouse click is an event we're interested in processing,
// we have discussed limiting to external links which go outside the
// react application and forcing implementers to use redux actions for
// interal links, however the app is not implemented like that in
// places, eg: Used Search List. so we're not enforcing that restriction
if (!isLeftClickEvent(event)) {
return
}

// Track only events when triggered from a element that has
// the `analytics` data attribute.
if (event.target.dataset.analytics !== undefined) {
trackingManager.event('pageName', 'User')
}
}

_handlePageView = route => {
console.log('CHANGE PAGE EVENT')
console.log(route)
}

/**
* Return tracking script.
*/
_renderTrackingScript() {

/**
* If utag is already loaded on the page we don't want to load it again
*/
if (window.utag !== undefined) return

if (config.useTagManager === false) return

/**
* Load utag script.
*/
return (
<ScriptManager
account={config.tagManagerAccount}
profile={config.tagManagerProfile}
environment={config.tagManagerEnvironment}
/>
)
}


render() {
return (
<React.Fragment>
<Application {...this.props} {...this.state} />
{this.props.children}
{this._renderTrackingScript()}
</React.Fragment>
)
}
}

export default track

我想用我的 index.js 做类似的事情:

import React from 'react'
import ReactDOM from 'react-dom'
import { Router, Switch, Route } from 'react-router-dom'
import { Provider } from 'react-redux'
import store from './lib/store'
import history from './lib/history'
import Loadable from 'react-loadable'
import PageLoader from './components/PageLoader/PageLoader'
import {
DEFAULT_PATH,
LOGIN_PATH,
LOGOUT_PATH,
USER_PATH,
} from './lib/paths'

const Login = Loadable({ loader: () => import('./scenes/Auth/Login' /* webpackChunkName: 'login' */), loading: PageLoader })
const Logout = Loadable({ loader: () => import('./scenes/Auth/Logout'/* webpackChunkName: 'logout' */), loading: PageLoader })
const User = Loadable({ loader: () => import('./scenes/Auth/User'/* webpackChunkName: 'user' */), loading: PageLoader })


import Track from './lib/tracking/Tracker'

import './assets/stylesheets/bootstrap.scss'
import './bootstrap-ds.css'
import './index.css'
import './assets/stylesheets/scenes.scss'

ReactDOM.render((
// This is an example of what I want to accomplish
<Track>
<Provider store={store}>
<Router history={history}>
<Switch>
<Route path={LOGIN_PATH} component={Login} />
<Route path={LOGOUT_PATH} component={Logout} />
<Route path={USER_PATH} component={User} />
</Switch>
</Router>
</Provider>
</Track>
), document.getElementById('root'))

所以,基本上 <Track> 在哪里组件可以包装整个应用程序并仍然使用 Prop 并检查它们是否更新。有没有办法做到这一点?我需要更改什么?

最佳答案

Context API似乎是您的用例。您需要一种解耦的方式来在同一棵树中的组件之间共享数据。您的包装器可以实现一个 Provider,所有对共享值感兴趣的组件都将实现一个 ConsumerHOCrender Props 可用于共享有状态逻辑,而不是状态本身。

const { Provider, Consumer } = React.createContext()

const Wrapper = ({children}) =>{
return(
<Provider value={mySharedValue}>
{children}
</Provider>
)
}

const NestedChildren = () =>{
return(
<Consumer>
{context => <div>{context}</div>}
</Consumer>
)
}

const App = () =>{
return(
<Wrapper>
<Child> <NestedChild /> </Child>
</Wrapper>
)
}

关于javascript - 如何为整个应用程序创建包装器组件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57204995/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com