首页 > 解决方案 > 使用 React 组件处理我网站上的所有文本

问题描述

在我的 React 应用程序中,为了处理我的体育分析网站不同部分所需的所有(大部分)文本,我构建了一个组件<PageText>. 整个网站都需要文字来解释图表和统计表的细节,一般来说,整个网站都需要文字,我想将所有这些文字集中在一个地方。我认为创建一个组件会比<p>在我的 25 到 50 个不同的容器组件中散布具有不同文本/样式等的数十个(很快数百个)标签更好的方法。

当我打电话时<PageText>,它看起来像这样:

<PageText usedFor='section' pageName='TeamLanding' textNum={2} />
<PageText usedFor='section' playerName={playerFullName} teamName={teamNameMarket} pageName='PlayerLineups' />
<PageText usedFor='table' tableName='TeamSeason' textNum={1} />
...etc

他们采用强制性道具usedFortextNum,以及在特定文本句子中使用的十几个(并且不断增长的)可选道具。

这是组件的全部内容PageText(不需要阅读整个内容,只需略读结构即可):

import { Link } from 'react-router-dom';
import React from 'react';

function PageText({ usedFor, pageName, tableName, teamName, playerName, confName, chartName, scope, textNum, shotData, lineupScope, numQualTeams, sizeAdj = 1 }) {

    PageText.defaultProps = {
        sizeAdj: 1,
        textNum: 1,
        confName: 'MEGA'
    };

    let brandBlue = '#0066CC';

    // Styles
    let sectionStyle = { fontSize: `calc(${sizeAdj} * 1em)`, fontStyle: 'italic', lineHeight: '1.25' };
    let tableStyle = { fontSize: `calc(${sizeAdj} * 0.85em)`, fontStyle: 'italic', lineHeight: '1.25', paddingTop: '3px', margin: 0 };
    let moreInfoStyles = { padding: '8px' };

    // each userFor + pageName pairing has 3 different texts to show. 
    let text1, text2, text3;

    // usedFor: ['section', 'table', 'moreInfo';
    // usedFor helps with segmenting the texts into groups, and are used to style the <p> tags differently based on use of text. 
    //pageName: all of the different names of pages on my website (the parent components where text will be displayed)

    if (usedFor === 'section') {
        switch (pageName) {
            case 'TeamLanding':
                text1 = <p style={sectionStyle}>The tables below display team-season statistics.</p>;
                text2 = <p style={sectionStyle}><span style={{ color: brandBlue, fontWeight: '700' }}>Trial Access:</span> Team-season statistics available for trial teams only - sign up for a full subscription to access statistics for all available NCAA teams.</p>;
                text3 = <p style={sectionStyle}><span style={{ color: brandBlue, fontWeight: '700' }}>Tips:</span> Tables are interactive. Table headers are hoverable (help tooltip) and clickable (sort columns). Logos and names within tables are hyperlinks useful for website navigation.</p>;
                break;
            case 'TeamScatter':
                text1 = <p style={sectionStyle}>Welcome to the <span style={{ fontWeight: '700', color: '#0066CC' }}>Team-Verse Logo Plotting Application</span> - designed to visually compare teams across your choice of team stats. Use the select widgets below to toggle between seasons, to filter by conference, and to select the stats for each axis. Tips - use the "Suggested Graphs" widget to automatically select between statistical pairings for the axes that intuitively go well together, or click the "Random Axes" button to randomly select statistics for the axes. Also, toggle the "Exc/Inc Opp Stats" button to add opponent stats (stats each team allowed to opponents) to the X-Axis and Y-Axis select widgets.</p>;

                break;
            case 'TeamPlayerStats':
                text1 = <p style={sectionStyle}>The tables below display player-season statistics for {teamName}. The large yellow/orange/red numbers show each player's <span style={{ color: brandBlue, fontWeight: 700 }}> 0 - 100 percentile rating </span>in that statistic, with 100 being the best and 0 the worst. The minutes filter below can be used to change the minumum-minutes requirement to appear in the tables below. Column headers are hoverable and include a short explanation of the stat.</p>;
                text2 = <p style={sectionStyle}>The Assister-Scorer Network is a graph consisting of nodes (for each player) and links (for each pair of players) that represents the frequency with which players on {teamName} assist each other’s baskets - the graph helps to answer the question “Who is assisting who on this team?”&lt;/p>;
                text3 = <p style={sectionStyle}><span style={{ color: brandBlue, fontWeight: '700' }}>Tips:</span> Hover a node to reveal its tooltip, or click on a node to reverse the direction of the arrows / links. Use the select to choose the number of players to display in the network graph, but beware of including too many players, which will clutter the graph. Click the Show ROP (rest of players) button to display additional nodes for bench players on the team not included in the base graph.</p>;
                break;
            case 'TeamGameRecaps':
                text1 = <p style={sectionStyle}>The tables below display team-game boxscore statistics for {teamName}. Use the select widget below to choose between the 6 different table options. Use the table headers to sort the columns, revealing the team's best and worst games for each statistic, and helping to uncover which statistics are most correlated with winning and losing games.</p>;
                text2 = <p style={sectionStyle}>The graph below displays, for the selected statistic, {teamName}'s performance in that statistic for each game, along with their 5-game rolling average for that statistic. Note that toggling the table select widget above will update the graph select widget below with different stat options for the graph.</p>;
                break;                
            case 'PlayerLanding':
                text1 = <p style={sectionStyle}>The table below displays player-season statistics and percentile ratings across all division-I players. Use the select widgets to choose amongst the 5 different tables (Offensive, Defensive, Shooting Overall, Shooting By Distance, Shooting by Court Zone), and to filter these tables for players from specific conferences. Note that statistics in the <strong>Shooting By Distance</strong> and <strong>Shooting By Court Zone</strong> tables are computed using play-by-play data that is not available for all division-I basketball games.</p>;
                text2 = <p style={sectionStyle}><span style={{ color: brandBlue, fontWeight: '700' }}>Trial Access:</span> Player-season statistics available for players on trial teams only - sign up for a full subscription to access statistics for all available NCAA players. Conference filter disabled on trial accounts.</p>;
                text3 = <p style={sectionStyle}><span style={{ color: brandBlue, fontWeight: '700' }}>Tips:</span> Tables are interactive. Table headers are hoverable (short stat explanations) and clickable (sortable columns), and logos and player names within the table are hyperlinks useful for navigation of the platform.</p>;
                break;
            case 'PlayerScatter':
                text1 = <p style={sectionStyle}>Use the player-verse scatter plotting application to compare players across chosen statistics. Use the select widgets below to toggle the various graph filters, and to change the stats on each axis. See below for additional information.</p>;
                break;
            case 'PlayerComps':
                text1 = <p style={sectionStyle}>CBB Comps is a model for computing similarity scores across players using selected metrics, where scores are computed based solely on the differences between the player's percentile rankings in the selected metrics. Choose your own metrics below, and see which players are most similar to {playerName} across those metrics. Similarity scores range from a minimum of -100 (zero similarity) to +100 (perfect similarity).</p>;
                break;
            case 'GameRecaps':
                text1 = <p style={sectionStyle}>Each team's statistical performance is summarized below, with key game statistics grouped into 6 categories: (1) Ball Control, (2) Shooting, (3) Play Style, (4) Four Factors, (5) Scoring by Play Context, and (6) Defense. Black numbers reflect the raw stat values, and the large yellow/orange/red numbers reflect each team's <span style={{ color: brandBlue, fontWeight: 700 }}> 0 - 100 percentile rating </span>for all games played by all teams in that statistic for the season, with 100 being the best game and 0 being the worst game.</p>;
                text2 = <p style={sectionStyle}>Marker Charts and Heatmaps for each team's shooting performance in this game - use the button above to the right to toggle between graph types, and to toggle the level of detail in the graphs. Note that heatmaps suffer from a small-sample-size challenge for single games.</p>;
                text3 = <p style={sectionStyle}>Break down each team's shooting performance at the most detailed level. Shooting by zone / by distance graphs highlight the effectiveness and frequency of team shooting by region of the court. Use the buttons above to the right to toggle between zone and distance graphs, and to toggle the level of detail in the graphs.</p>;
                break;
            default: text1 = ``; text2 = ``; text3 = ``;
        }
    }

    if (usedFor === 'table') {
        switch (tableName) {
            case 'TeamSeason':
                text1 = <p style={tableStyle}>Black numbers reflect stat values, and large colored numbers reflect each team's <strong>{scope === 'conf' ? 'Conference' : 'Division-I'} ranking</strong>> in each stat, against {scope === 'conf' ? `opposing teams in the ${confName}` : `all Division-I teams`}.</p>;
                text2 = <p style={tableStyle}>Due to limited availability of play-by-play data with shooting coordinates for smaller-conference schools, <strong>only {numQualTeams} teams</strong> qualify for detailed shooting rankings.</p>;
                text3 = <p style={tableStyle}>Large colored numbers reflect each team's <strong>conference ranking</strong> in each stat, against opposing teams in the {confName}.</p>;
                break;
            case 'PlayerSeason': text1 = <p style={tableStyle}>Black numbers reflect stat values, and large colored numbers reflect each player's <strong>0 - 100 percentile rating</strong> for each stat, across qualifying players in the top 6 conferences.</p>; break;
            case 'TeamGame': text1 = <p style={tableStyle}>Black numbers reflect stat values, and large yellow/orange/red numbers reflect the team's <strong>0 - 100 percentile rating</strong> in each game, compared to games played by all teams in that stat for the season.</p>; break;
            default: text1 = ``; text2 = ``; text3 = ``;
        }
    }

    if (usedFor === 'moreInfo') {
        switch (pageName) {
            case 'PlayerScatter':
                text1 =
                    (<div style={moreInfoStyles}>
                        <p>The Player-Verse is a scatter plotting application for comparing players across selected statistics. tables below display team-season statistics for teams that play in the top 6 division-I basketball conferences (ACC, Big East, Big 12, Big 10, SEC, Pac12), along with the OVC (Ohio Valley Conference) temporarily. Note that column headers are hoverable (include a short explanation of the stat) and clickable (to sort the columns). Tip - click on the conference logos, team logos, and team names within the tables to navigate to various pages on the website.</p>
                        <p>The tables below display team-season statistics for teams that play in the top 6 division-I basketball conferences (Ation of the stat) and clickable (to sort the columns). Tip - click on the conference logos, team logos, and team names within the tables to navigate to various pages on the website.</p>
                        <p>The tables below display team-season statistics for teams that play in the top 6 division-I basketball conferences (ACC, Big East, Big 12, Big 10, SEC, Pac12), along with the OVC (Ohio Valley Conpages on the website.</p>
                    </div>);
                break;
            case 'ShotCharts':
                text1 =
                    (<div style={moreInfoStyles}>
                        <div>
                            <div className='checkbox-btn' style={{ display: 'inline-block' }}>
                                <input
                                    style={{ margin: '0' }}
                                    type='checkbox'
                                    className='checkbox'
                                />
                                <div className='toggler' data-label-checked='Yes' data-label-unchecked='No' />
                            </div>
                            <p style={{ marginLeft: '10px', display: 'inline' }}><strong>Appwide vs. Chartwide: </strong> Use the "Yes/No" toggle switches to switch the scope of the select widgets and other buttons between Appwide and Chartwide. Appwide widgets (the main row of selects atop the page) control all 4 shot charts at once, whereas chartwide widgets (appear upon toggling) control their specific shot chart.</p>
                        </div>
                        <p style={{ marginTop: '1rem' }}><strong>Att Freq & FG Pct:</strong> Our "region" chart types (Zone and Dist) include the option to display either (a) net field goal percentages (FG%), or (b) net field goal attempt frequency (FGA Freq), as the metric used for coloring the graph. FG% shot charts provide insights into how effective a team shoots from a particular location, whereas FGA Freq shot charts provide insight into how frequently a team shoots from a particular location, all relative to league average.</p>
                        <p><strong>Offense & Defense:</strong> In addition to the standard offensive shot charts, the shot visualizer is also able to generate defensive shot charts at the team level via the "Offense/Defense" button, providing unique insights into the defensive shot profile that each team allows.</p>
                        <p><strong>Navigate Faster:</strong> This helper select allows you to quickly load several shot charts that pair well together with a single click. For example, selecting "Team's Top 4 Players" will identify the 4 players on the first team (the team whose shot chart is in the top-left) with the most shot attempts, and load all 4 of their shot charts. Note that each of the options in this helper select load charts for the first team, so select the team you'd like in the first chart before using the helper select.</p>
                    </div>);
                break;
            default:
                text1 = ``;
        }
    }

    let returnText;
    switch (textNum) {
        case 1: returnText = text1; break;
        case 2: returnText = text2; break;
        case 3: returnText = text3; break;
        default: returnText = text1;
    }

    return (
        returnText
    );
}

export default PageText;

简而言之,我最初认为这是一种聪明的方法,因为我重复了<p>在所有容器组件中放置标签的任务。然而,目前该组件感觉好像它构建得不好,并且似乎受到很大限制,特别是:

    <h3 className='small-graph-header'>{graph1XStat.fullName}</h3>
    <h3 className='shot-chart-sub-header'>Defensive Heatmap Allowed</h3>
    <h3 style={{ margin: '0 0 10px 0', textDecoration: 'underline', textDecorationColor: '#0066CC' }}>Defensive Shooting Allowed</h3>

这些<h>标签本身在我的网站上看起来也很混乱,因为我有时会为它们使用 className,有时还会使用内联样式。

我的一部分认为我可以通过简单地为不需要悬停或其他效果的所有 h 和 p 标签进行内联样式来简化这一点(废弃这个组件),但我也喜欢一个组件来组织所有这个。有一个更好的方法吗?我很好奇在使用 React 构建的网站上组织所有文本的首选方法通常是什么?我知道在 React 中有不同的方法可以做同样的事情,但是在这里了解一般的最佳实践会很有帮助。

编辑:通过输入并重新阅读帖子,对我来说更明显的是,我喜欢将文本集中在单个组件中的想法,但我没有正确设置不同的 p-tags 样式。我也不喜欢越来越多的道具,也不喜欢访问每个句子的复杂方式(usedFor、textNum、pageName 等道具)。

标签: javascriptcssreactjstextcomponents

解决方案


在我公认的有限经验中,React 旨在 a) 模块化构建 DOM 结构(您的用户界面)和 b) 管理状态。

据我所知,您正在尝试使用 Reactjs 来管理事物的外观,这属于 CSS 领域,或者广义上的样式。虽然我没有针对您的代码的建议,但处理此问题的更好方法是使用众多工具包中的一种来使 CSS 更加模块化,例如 Styled、emotion 或模块化 CSS。

那里有很多选择;为了使决定更容易,请阅读他们的介绍性文档,看看是否可以将它们逐步添加到您的项目中。你总是可以创建一个分支,如果它适合你(如果适用的话,你的团队)。

如果您对那里的内容感到好奇,可以了解更多: JS 中的最佳:JS 工具中的 CSS


推荐阅读